Compare commits

...
47 Commits
Author SHA1 Message Date
moloch-- 4a996b5494 Fix issue #1055 and #1054 2023-01-04 09:04:36 -08:00
Joe 0910c28a5f Merge pull request #1053 from BishopFox/a3sroot-fix/gzip
A3sroot fix/gzip
2023-01-03 15:21:05 -08:00
moloch-- ff3e37075b Fix hex unit test 2023-01-03 14:33:31 -08:00
moloch-- 41c95a9570 Minor tweaks 2023-01-03 14:23:03 -08:00
dependabot[bot] 6e87b94035 Bump github.com/shirou/gopsutil/v3 from 3.22.11 to 3.22.12
Bumps [github.com/shirou/gopsutil/v3](https://github.com/shirou/gopsutil) from 3.22.11 to 3.22.12.
- [Release notes](https://github.com/shirou/gopsutil/releases)
- [Commits](https://github.com/shirou/gopsutil/commits/v3.22.12)

---
updated-dependencies:
- dependency-name: github.com/shirou/gopsutil/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2023-01-03 14:09:02 -08:00
dependabot[bot] 06b2e4ecc1 Bump gorm.io/driver/postgres from 1.4.5 to 1.4.6
Bumps [gorm.io/driver/postgres](https://github.com/go-gorm/postgres) from 1.4.5 to 1.4.6.
- [Release notes](https://github.com/go-gorm/postgres/releases)
- [Commits](https://github.com/go-gorm/postgres/compare/v1.4.5...v1.4.6)

---
updated-dependencies:
- dependency-name: gorm.io/driver/postgres
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2023-01-03 14:09:01 -08:00
moloch-- db9bc1317a Tweak downloaded flag file, and add it to make clean-all 2023-01-03 14:08:59 -08:00
James Golovich 7e8d228314 Automatically run go-assets.sh from Makefile if it hasn't been run already 2023-01-03 14:08:13 -08:00
necroph0s 29340acfee Add flag to disable sgn when generating beacon shellcode 2023-01-03 14:07:37 -08:00
moloch-- 067eb5856e Signed fix for pr #995 2023-01-03 14:07:37 -08:00
dependabot[bot] fa58a52cae Bump github.com/pquerna/otp from 1.3.0 to 1.4.0
Bumps [github.com/pquerna/otp](https://github.com/pquerna/otp) from 1.3.0 to 1.4.0.
- [Release notes](https://github.com/pquerna/otp/releases)
- [Commits](https://github.com/pquerna/otp/compare/v1.3.0...v1.4.0)

---
updated-dependencies:
- dependency-name: github.com/pquerna/otp
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
2023-01-03 14:07:36 -08:00
dependabot[bot] 3ac0ff131a Bump gorm.io/driver/sqlite from 1.4.3 to 1.4.4
Bumps [gorm.io/driver/sqlite](https://github.com/go-gorm/sqlite) from 1.4.3 to 1.4.4.
- [Release notes](https://github.com/go-gorm/sqlite/releases)
- [Commits](https://github.com/go-gorm/sqlite/compare/v1.4.3...v1.4.4)

---
updated-dependencies:
- dependency-name: gorm.io/driver/sqlite
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2023-01-03 14:07:36 -08:00
s3cst4rs cc55f38195 Fix the bug of the corresponding relationship between dwLogonType and dwLogonProvider in MakeToken 2023-01-03 14:07:35 -08:00
Tom Samstag 35eedd75ec install script- use users' primary group name
The install script previously assumed that users were each a member of a
group named the same as their username. While this is a convention on
some systems, it's not universal. This change determines users' primary
group name for chown'ing their client config directory instead of making
this assumption.
2023-01-03 14:07:34 -08:00
rkervella 5067333eff Only alert user when --in-process is not used. 2023-01-03 14:07:33 -08:00
dependabot[bot] 0d1c64aede Bump golang.org/x/sys from 0.2.0 to 0.3.0
Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.2.0 to 0.3.0.
- [Release notes](https://github.com/golang/sys/releases)
- [Commits](https://github.com/golang/sys/compare/v0.2.0...v0.3.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sys
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
2023-01-03 14:07:33 -08:00
James Golovich 98f2340e3e Ensure Wireguard endpoint is valid before trying to use it
Fixes #931
2023-01-03 14:07:32 -08:00
dependabot[bot] bf7ac3997d Bump nokogiri from 1.13.9 to 1.13.10 in /docs
Bumps [nokogiri](https://github.com/sparklemotion/nokogiri) from 1.13.9 to 1.13.10.
- [Release notes](https://github.com/sparklemotion/nokogiri/releases)
- [Changelog](https://github.com/sparklemotion/nokogiri/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sparklemotion/nokogiri/compare/v1.13.9...v1.13.10)

---
updated-dependencies:
- dependency-name: nokogiri
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
2023-01-03 14:07:31 -08:00
dependabot[bot] 0c827c6736 Bump github.com/shirou/gopsutil/v3 from 3.22.10 to 3.22.11
Bumps [github.com/shirou/gopsutil/v3](https://github.com/shirou/gopsutil) from 3.22.10 to 3.22.11.
- [Release notes](https://github.com/shirou/gopsutil/releases)
- [Commits](https://github.com/shirou/gopsutil/commits)

---
updated-dependencies:
- dependency-name: github.com/shirou/gopsutil/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2023-01-03 14:07:30 -08:00
dependabot[bot] b8723d93da Bump github.com/jedib0t/go-pretty/v6 from 6.4.2 to 6.4.3
Bumps [github.com/jedib0t/go-pretty/v6](https://github.com/jedib0t/go-pretty) from 6.4.2 to 6.4.3.
- [Release notes](https://github.com/jedib0t/go-pretty/releases)
- [Commits](https://github.com/jedib0t/go-pretty/compare/v6.4.2...v6.4.3)

---
updated-dependencies:
- dependency-name: github.com/jedib0t/go-pretty/v6
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2023-01-03 14:07:28 -08:00
dependabot[bot] 96d242b0df Bump golang.org/x/text from 0.4.0 to 0.5.0
Bumps [golang.org/x/text](https://github.com/golang/text) from 0.4.0 to 0.5.0.
- [Release notes](https://github.com/golang/text/releases)
- [Commits](https://github.com/golang/text/compare/v0.4.0...v0.5.0)

---
updated-dependencies:
- dependency-name: golang.org/x/text
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
2023-01-03 14:07:25 -08:00
rkervella 645e5e0d14 Apply new logic to the downloadHandler 2023-01-03 14:07:24 -08:00
rkervella 2a2b7dbf47 Wrap filepath.Match into a custom package for windows specific code. 2023-01-03 14:07:22 -08:00
rkervella 206ab56bee Refactor to remove ioutil dep 2023-01-03 14:07:16 -08:00
rkervella 362efc8f9d Update implant vendor 2023-01-03 14:07:13 -08:00
Joe cf7f4be3ed Merge pull request #1049 from BishopFox/0654dependabot/go_modules/github.com/shirou/gopsutil/v3-3.22.12
Bump github.com/shirou/gopsutil/v3 from 3.22.11 to 3.22.12
2023-01-03 14:02:34 -08:00
dependabot[bot] 0796409887 Bump github.com/shirou/gopsutil/v3 from 3.22.11 to 3.22.12
Bumps [github.com/shirou/gopsutil/v3](https://github.com/shirou/gopsutil) from 3.22.11 to 3.22.12.
- [Release notes](https://github.com/shirou/gopsutil/releases)
- [Commits](https://github.com/shirou/gopsutil/commits/v3.22.12)

---
updated-dependencies:
- dependency-name: github.com/shirou/gopsutil/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2023-01-03 21:10:12 +00:00
Joe 30647d267a Merge pull request #1048 from BishopFox/3a7cdependabot/go_modules/gorm.io/driver/postgres-1.4.6
Bump gorm.io/driver/postgres from 1.4.5 to 1.4.6
2023-01-03 13:07:47 -08:00
Joe 65da9c8504 Merge pull request #1052 from BishopFox/jamesgol-auto-go-assets
Jamesgol auto go assets
2023-01-03 13:06:35 -08:00
Ronan Kervella e296b6fdc7 Merge pull request #1050 from necroph0s/disable-sgn
Add flag to disable sgn when generating beacon shellcode
2023-01-03 12:33:12 -08:00
Ronan Kervella 3e3fdbe6a8 Merge pull request #1051 from BishopFox/fix/995
Signed fix for pr #995
2023-01-03 12:27:53 -08:00
moloch-- 8d97ba3aec Tweak downloaded flag file, and add it to make clean-all 2023-01-03 12:16:46 -08:00
dependabot[bot] a5a60a505c Bump github.com/pquerna/otp from 1.3.0 to 1.4.0
Bumps [github.com/pquerna/otp](https://github.com/pquerna/otp) from 1.3.0 to 1.4.0.
- [Release notes](https://github.com/pquerna/otp/releases)
- [Commits](https://github.com/pquerna/otp/compare/v1.3.0...v1.4.0)

---
updated-dependencies:
- dependency-name: github.com/pquerna/otp
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
2023-01-03 11:56:10 -08:00
dependabot[bot] c04f3f0228 Bump gorm.io/driver/sqlite from 1.4.3 to 1.4.4
Bumps [gorm.io/driver/sqlite](https://github.com/go-gorm/sqlite) from 1.4.3 to 1.4.4.
- [Release notes](https://github.com/go-gorm/sqlite/releases)
- [Commits](https://github.com/go-gorm/sqlite/compare/v1.4.3...v1.4.4)

---
updated-dependencies:
- dependency-name: gorm.io/driver/sqlite
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2023-01-03 11:56:09 -08:00
s3cst4rs 885387b3ea Fix the bug of the corresponding relationship between dwLogonType and dwLogonProvider in MakeToken 2023-01-03 11:56:08 -08:00
Tom Samstag d809a28a5d install script- use users' primary group name
The install script previously assumed that users were each a member of a
group named the same as their username. While this is a convention on
some systems, it's not universal. This change determines users' primary
group name for chown'ing their client config directory instead of making
this assumption.
2023-01-03 11:56:07 -08:00
rkervella f48dfa0e4b Only alert user when --in-process is not used. 2023-01-03 11:56:06 -08:00
dependabot[bot] 0bf19f5242 Bump golang.org/x/sys from 0.2.0 to 0.3.0
Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.2.0 to 0.3.0.
- [Release notes](https://github.com/golang/sys/releases)
- [Commits](https://github.com/golang/sys/compare/v0.2.0...v0.3.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sys
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
2023-01-03 11:56:05 -08:00
James Golovich 7bea0ee08f Ensure Wireguard endpoint is valid before trying to use it
Fixes #931
2023-01-03 11:56:04 -08:00
dependabot[bot] 4df0e87896 Bump nokogiri from 1.13.9 to 1.13.10 in /docs
Bumps [nokogiri](https://github.com/sparklemotion/nokogiri) from 1.13.9 to 1.13.10.
- [Release notes](https://github.com/sparklemotion/nokogiri/releases)
- [Changelog](https://github.com/sparklemotion/nokogiri/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sparklemotion/nokogiri/compare/v1.13.9...v1.13.10)

---
updated-dependencies:
- dependency-name: nokogiri
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
2023-01-03 11:56:04 -08:00
dependabot[bot] 35f1fdd6cb Bump github.com/shirou/gopsutil/v3 from 3.22.10 to 3.22.11
Bumps [github.com/shirou/gopsutil/v3](https://github.com/shirou/gopsutil) from 3.22.10 to 3.22.11.
- [Release notes](https://github.com/shirou/gopsutil/releases)
- [Commits](https://github.com/shirou/gopsutil/commits)

---
updated-dependencies:
- dependency-name: github.com/shirou/gopsutil/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2023-01-03 11:56:03 -08:00
dependabot[bot] 19ccc10a25 Bump github.com/jedib0t/go-pretty/v6 from 6.4.2 to 6.4.3
Bumps [github.com/jedib0t/go-pretty/v6](https://github.com/jedib0t/go-pretty) from 6.4.2 to 6.4.3.
- [Release notes](https://github.com/jedib0t/go-pretty/releases)
- [Commits](https://github.com/jedib0t/go-pretty/compare/v6.4.2...v6.4.3)

---
updated-dependencies:
- dependency-name: github.com/jedib0t/go-pretty/v6
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2023-01-03 11:56:02 -08:00
dependabot[bot] b900af8b21 Bump golang.org/x/text from 0.4.0 to 0.5.0
Bumps [golang.org/x/text](https://github.com/golang/text) from 0.4.0 to 0.5.0.
- [Release notes](https://github.com/golang/text/releases)
- [Commits](https://github.com/golang/text/compare/v0.4.0...v0.5.0)

---
updated-dependencies:
- dependency-name: golang.org/x/text
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
2023-01-03 11:56:00 -08:00
dependabot[bot] f0de5eb2d1 Bump gorm.io/driver/postgres from 1.4.5 to 1.4.6
Bumps [gorm.io/driver/postgres](https://github.com/go-gorm/postgres) from 1.4.5 to 1.4.6.
- [Release notes](https://github.com/go-gorm/postgres/releases)
- [Commits](https://github.com/go-gorm/postgres/compare/v1.4.5...v1.4.6)

---
updated-dependencies:
- dependency-name: gorm.io/driver/postgres
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2023-01-03 19:41:52 +00:00
necroph0s ea045fb1a6 Add flag to disable sgn when generating beacon shellcode 2023-01-03 14:11:20 -05:00
James Golovich 7b6ff79b5f Automatically run go-assets.sh from Makefile if it hasn't been run already 2022-12-02 18:37:45 -08:00
a3sroot 0ec79a8e55 gzip frequent object creation can lead to memory leaks 2022-12-01 15:46:05 +08:00
360 changed files with 23704 additions and 34145 deletions

No files matched your search

+3
View File
@@ -42,3 +42,6 @@ sliver-server-windows.zip
.DS_Store
dist/
# Flag to show that go-assets.sh has been run
.downloaded_assets
+11 -6
View File
@@ -118,32 +118,32 @@ endif
# Targets
#
.PHONY: default
default: clean validate-go-version
default: clean .downloaded_assets validate-go-version
$(ENV) $(GO) build -mod=vendor -trimpath $(TAGS),server $(LDFLAGS) -o sliver-server$(ARTIFACT_SUFFIX) ./server
$(ENV) $(GO) build -mod=vendor -trimpath $(TAGS),client $(LDFLAGS) -o sliver-client$(ARTIFACT_SUFFIX) ./client
.PHONY: macos
macos: clean validate-go-version
macos: clean .downloaded_assets validate-go-version
GOOS=darwin GOARCH=amd64 $(ENV) $(GO) build -mod=vendor -trimpath $(TAGS),server $(LDFLAGS) -o sliver-server$(ARTIFACT_SUFFIX) ./server
GOOS=darwin GOARCH=amd64 $(ENV) $(GO) build -mod=vendor -trimpath $(TAGS),client $(LDFLAGS) -o sliver-client$(ARTIFACT_SUFFIX) ./client
.PHONY: macos-arm64
macos-arm64: clean validate-go-version
macos-arm64: clean .downloaded_assets validate-go-version
GOOS=darwin GOARCH=arm64 $(ENV) $(GO) build -mod=vendor -trimpath $(TAGS),server $(LDFLAGS) -o sliver-server$(ARTIFACT_SUFFIX) ./server
GOOS=darwin GOARCH=arm64 $(ENV) $(GO) build -mod=vendor -trimpath $(TAGS),client $(LDFLAGS) -o sliver-client$(ARTIFACT_SUFFIX) ./client
.PHONY: linux
linux: clean validate-go-version
linux: clean .downloaded_assets validate-go-version
GOOS=linux GOARCH=amd64 $(ENV) $(GO) build -mod=vendor -trimpath $(TAGS),server $(LDFLAGS) -o sliver-server$(ARTIFACT_SUFFIX) ./server
GOOS=linux GOARCH=amd64 $(ENV) $(GO) build -mod=vendor -trimpath $(TAGS),client $(LDFLAGS) -o sliver-client$(ARTIFACT_SUFFIX) ./client
.PHONY: linux-arm64
linux-arm64: clean validate-go-version
linux-arm64: clean .downloaded_assets validate-go-version
GOOS=linux GOARCH=arm64 $(ENV) $(GO) build -mod=vendor -trimpath $(TAGS),server $(LDFLAGS) -o sliver-server$(ARTIFACT_SUFFIX) ./server
GOOS=linux GOARCH=arm64 $(ENV) $(GO) build -mod=vendor -trimpath $(TAGS),client $(LDFLAGS) -o sliver-client$(ARTIFACT_SUFFIX) ./client
.PHONY: windows
windows: clean validate-go-version
windows: clean .downloaded_assets validate-go-version
GOOS=windows $(ENV) $(GO) build -mod=vendor -trimpath $(TAGS),server $(LDFLAGS) -o sliver-server$(ARTIFACT_SUFFIX).exe ./server
GOOS=windows $(ENV) $(GO) build -mod=vendor -trimpath $(TAGS),client $(LDFLAGS) -o sliver-client$(ARTIFACT_SUFFIX).exe ./client
@@ -178,7 +178,12 @@ clean-all: clean
rm -rf ./server/assets/fs/windows/amd64
rm -rf ./server/assets/fs/linux/amd64
rm -f ./server/assets/fs/*.zip
rm -f ./.downloaded_assets
.PHONY: clean
clean:
rm -f sliver-client sliver-server sliver-*.exe
.downloaded_assets:
./go-assets.sh
touch ./.downloaded_assets
+4
View File
@@ -1328,6 +1328,7 @@ func BindCommands(con *console.SliverConsoleClient) {
f.Bool("l", "skip-symbols", false, "skip symbol obfuscation")
f.String("I", "template", "sliver", "implant code template")
f.Bool("E", "external-builder", false, "use an external builder")
f.Bool("G", "disable-sgn", false, "disable shikata ga nai shellcode encoder")
f.String("c", "canary", "", "canary domain(s)")
@@ -1388,6 +1389,7 @@ func BindCommands(con *console.SliverConsoleClient) {
f.Bool("l", "skip-symbols", false, "skip symbol obfuscation")
f.String("I", "template", "sliver", "implant code template")
f.Bool("E", "external-builder", false, "use an external builder")
f.Bool("G", "disable-sgn", false, "disable shikata ga nai shellcode encoder")
f.String("c", "canary", "", "canary domain(s)")
@@ -1540,6 +1542,7 @@ func BindCommands(con *console.SliverConsoleClient) {
f.Bool("d", "debug", false, "enable debug features")
f.Bool("e", "evasion", false, "enable evasion features")
f.Bool("l", "skip-symbols", false, "skip symbol obfuscation")
f.Bool("G", "disable-sgn", false, "disable shikata ga nai shellcode encoder")
f.String("c", "canary", "", "canary domain(s)")
@@ -1598,6 +1601,7 @@ func BindCommands(con *console.SliverConsoleClient) {
f.Int64("M", "minutes", 0, "beacon interval minutes")
f.Int64("S", "seconds", 60, "beacon interval seconds")
f.Int64("J", "jitter", 30, "beacon interval jitter in seconds")
f.Bool("G", "disable-sgn", false, "disable shikata ga nai shellcode encoder")
// Generate flags
f.String("o", "os", "windows", "operating system")
+4 -3
View File
@@ -346,6 +346,7 @@ func parseCompileFlags(ctx *grumble.Context, con *console.SliverConsoleClient) *
C2: c2s,
CanaryDomains: canaryDomains,
TemplateName: ctx.Flags.String("template"),
DisableSGN: ctx.Flags.Bool("disable-sgn"),
WGPeerTunIP: tunIP.String(),
WGKeyExchangePort: uint32(ctx.Flags.Int("key-exchange")),
@@ -791,9 +792,9 @@ func compile(config *clientpb.ImplantConfig, save string, con *console.SliverCon
fileData := generated.File.Data
if config.IsShellcode {
confirm := false
survey.AskOne(&survey.Confirm{Message: "Encode shellcode with shikata ga nai?"}, &confirm)
if confirm {
if config.DisableSGN {
con.PrintErrorf("Shikata ga nai encoder is %sdisabled%s\n", console.Bold, console.Normal)
} else {
con.PrintInfof("Encoding shellcode with shikata ga nai ... ")
resp, err := con.Rpc.ShellcodeEncoder(context.Background(), &clientpb.ShellcodeEncodeReq{
Encoder: clientpb.ShellcodeEncoder_SHIKATA_GA_NAI,
+2 -1
View File
@@ -23,6 +23,7 @@ import (
"compress/zlib"
"context"
"encoding/binary"
"github.com/bishopfox/sliver/util/encoders"
"net/url"
"strconv"
"strings"
@@ -103,7 +104,7 @@ func StageListenerCmd(ctx *grumble.Context, con *console.SliverConsoleClient) {
zlibWriter.Close()
stage2 = compBuff.Bytes()
case "gzip":
stage2 = util.GzipBuf(stage2)
stage2 = encoders.GzipBuf(stage2)
case "deflate9":
fallthrough
case "deflate":
-1
View File
@@ -190,7 +190,6 @@ curl -L --fail --output $OUTPUT_DIR/darwin/$GO_ARCH_1/sgn.zip https://github.com
echo "curl -L --fail --output $OUTPUT_DIR/darwin/$GO_ARCH_2/sgn.zip https://github.com/moloch--/sgn/releases/download/v$SGN_VER/sgn_macos-$GO_ARCH_2.zip"
curl -L --fail --output $OUTPUT_DIR/darwin/$GO_ARCH_2/sgn.zip https://github.com/moloch--/sgn/releases/download/v$SGN_VER/sgn_macos-$GO_ARCH_2.zip
# end
echo -e "clean up: $WORK_DIR"
rm -rf $WORK_DIR
+8 -15
View File
@@ -32,17 +32,17 @@ require (
github.com/miekg/dns v1.1.50
github.com/moloch--/memmod v0.0.0-20211120144554-8b37cc654945
github.com/pquerna/otp v1.4.0
github.com/shirou/gopsutil/v3 v3.22.11
github.com/shirou/gopsutil/v3 v3.22.12
github.com/sirupsen/logrus v1.9.0
github.com/spf13/cobra v1.6.1
github.com/stretchr/testify v1.8.1
github.com/things-go/go-socks5 v0.0.3-0.20210722055343-24af464efe43
github.com/xlab/treeprint v1.1.0
github.com/yiya1989/sshkrb5 v0.0.0-20201110125252-a1455b75a35e
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90
golang.org/x/net v0.0.0-20220722155237-a158d28d115b
golang.org/x/crypto v0.4.0
golang.org/x/net v0.3.0
golang.org/x/sys v0.3.0
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
golang.org/x/term v0.3.0
golang.org/x/text v0.5.0
golang.zx2c4.com/wireguard v0.0.0-20220316235147-5aff28b14c24
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20220208144051-fde48d68ee68
@@ -50,9 +50,9 @@ require (
google.golang.org/protobuf v1.28.1
gopkg.in/AlecAivazis/survey.v1 v1.8.8
gorm.io/driver/mysql v1.4.4
gorm.io/driver/postgres v1.4.5
gorm.io/driver/postgres v1.4.6
gorm.io/driver/sqlite v1.4.4
gorm.io/gorm v1.24.1-0.20221019064659-5dd2bb482755
gorm.io/gorm v1.24.2
gvisor.dev/gvisor v0.0.0-20220817001344-846276b3dbc5
modernc.org/sqlite v1.19.3
)
@@ -83,14 +83,9 @@ require (
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-uuid v1.0.2 // indirect
github.com/inconshreveable/mousetrap v1.0.1 // indirect
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
github.com/jackc/pgconn v1.13.0 // indirect
github.com/jackc/pgio v1.0.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgproto3/v2 v2.3.1 // indirect
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect
github.com/jackc/pgtype v1.12.0 // indirect
github.com/jackc/pgx/v4 v4.17.2 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
github.com/jackc/pgx/v5 v5.2.0 // indirect
github.com/jcmturner/gofork v1.0.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
@@ -103,7 +98,6 @@ require (
github.com/mattn/go-isatty v0.0.16 // indirect
github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
@@ -118,7 +112,6 @@ require (
golang.org/x/tools v0.1.12 // indirect
golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224 // indirect
google.golang.org/genproto v0.0.0-20210722135532-667f2b7c528f // indirect
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect
gopkg.in/jcmturner/aescts.v1 v1.0.1 // indirect
gopkg.in/jcmturner/dnsutils.v1 v1.0.1 // indirect
gopkg.in/jcmturner/goidentity.v3 v3.0.0 // indirect
+36 -125
View File
@@ -19,8 +19,6 @@ github.com/Binject/universal v0.0.0-20210304094126-daefaa886313/go.mod h1:J3XDRl
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20201008132610-5f9e7b3c49cd h1:u7K2oMFMd8APDV3fM1j2rO3U/XJf1g1qC3DDTKou8iM=
github.com/BurntSushi/xgb v0.0.0-20201008132610-5f9e7b3c49cd/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
github.com/Microsoft/go-winio v0.5.1 h1:aPJp2QD7OOrhO5tQXqQoGSJc+DjDtWTGLOmNyAm6FgY=
github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
github.com/Ne0nd0g/go-clr v1.0.3 h1:xt92wwuqY23ZSC7RuHD3mKu3K22Bk5NNbxI803vojK4=
@@ -66,12 +64,9 @@ github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWH
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI=
github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -107,9 +102,7 @@ github.com/gen2brain/shm v0.0.0-20200228170931-49f9650110c5 h1:Y5Q2mEwfzjMt5+3u7
github.com/gen2brain/shm v0.0.0-20200228170931-49f9650110c5/go.mod h1:uF6rMu/1nvu+5DpiRLwusA6xB8zlkNoGzKn8lmYONUo=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
@@ -121,7 +114,6 @@ github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
github.com/gobwas/ws v1.1.0 h1:7RFti/xnNkMJnrK7D1yQ/iCIB5OrrY/54/H930kIbHA=
github.com/gobwas/ws v1.1.0/go.mod h1:nzvNcVha5eUziGrbxFCo6qFIojQHjJV5cLYIbezhfL0=
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gofrs/uuid v4.3.1+incompatible h1:0/KbAdpx3UXAx1kEOWHJeOkpbgRFGHVgv+CFIY7dBJI=
github.com/gofrs/uuid v4.3.1+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
@@ -154,7 +146,6 @@ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
@@ -179,53 +170,14 @@ github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68=
github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA=
github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE=
github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s=
github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o=
github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY=
github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
github.com/jackc/pgconn v1.13.0 h1:3L1XMNV2Zvca/8BYhzcRFS70Lr0WlDg16Di6SFGAbys=
github.com/jackc/pgconn v1.13.0/go.mod h1:AnowpAqO4CMIIJNZl2VJp+KrkAZciAkhEl0W0JIobpI=
github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c=
github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc=
github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA=
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg=
github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgproto3/v2 v2.3.1 h1:nwj7qwf0S+Q7ISFfBndqeLwSwxs+4DPsbRFjECT1Y4Y=
github.com/jackc/pgproto3/v2 v2.3.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg=
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=
github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM=
github.com/jackc/pgtype v1.12.0 h1:Dlq8Qvcch7kiehm8wPGIW0W3KsCCHJnRacKW0UM8n5w=
github.com/jackc/pgtype v1.12.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs=
github.com/jackc/pgx/v4 v4.17.2 h1:0Ut0rpeKwvIVbMQ1KbMBU4h6wxehBI535LK6Flheh8E=
github.com/jackc/pgx/v4 v4.17.2/go.mod h1:lcxIZN44yMIrWI78a5CpucdD14hX0SBDbNRvjDBItsw=
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.2.0 h1:NdPpngX0Y6z6XDFKqmFQaE+bCtkqzvQIOt1wvBlAqs8=
github.com/jackc/pgx/v5 v5.2.0/go.mod h1:Ptn7zmohNsWEsdxRawMzk3gaKma2obW+NWTnKa0S4nk=
github.com/jackc/puddle/v2 v2.1.2/go.mod h1:2lpufsF5mRHO6SuZkm0fNYxM6SWHfvyFj62KwNzgels=
github.com/jcmturner/gofork v1.0.0 h1:J7uCkflzTEhUZ64xqKnkDxq3kzc96ajM1Gli5ktUem8=
github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o=
github.com/jedib0t/go-pretty/v6 v6.4.3 h1:2n9BZ0YQiXGESUSR+6FLg0WWWE80u+mIz35f0uHWcIE=
@@ -245,24 +197,22 @@ github.com/kbinani/screenshot v0.0.0-20191211154542-3a185f1ce18f/go.mod h1:f8GY5
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/konsorten/go-windows-terminal-sequences v1.0.2/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/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.4/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
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/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80 h1:6Yzfa6GP0rIo/kULo2bwGEkFvCePZ3qHDDTC3/J9Swo=
github.com/lesnuages/go-winio v0.4.19 h1:lFDu1mnhg5em+8zTHO4ChSD11J56xkyE8m3N8IrVmbA=
github.com/lesnuages/go-winio v0.4.19/go.mod h1:rm7jf4kBcldxMeljR7c7XY1qVCBc+8z3PtSgkrT9Clk=
github.com/lesnuages/snitch v0.6.0 h1:vOao32MdYDHYDcTAq2CKszDh6Dn8Bv1Gmgc8uVh193U=
github.com/lesnuages/snitch v0.6.0/go.mod h1:RfXlAVJYL7gUoZ9VMMon4LqrPiAjC8x62Ntbse4a4s0=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8=
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/lxn/win v0.0.0-20210218163916-a377121e959e h1:H+t6A/QJMbhCSEH5rAuRxh+CtW96g0Or0Fxa9IKr4uc=
@@ -270,16 +220,12 @@ github.com/lxn/win v0.0.0-20210218163916-a377121e959e/go.mod h1:KxxjdtRkfNoYDCUP
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
@@ -305,12 +251,9 @@ github.com/moloch--/grumble v1.1.6/go.mod h1:r7j3ShNy5EmOsegRD2DzTutIaGiLiA3M5yB
github.com/moloch--/memmod v0.0.0-20211120144554-8b37cc654945 h1:m3yCfV8Vqp4MF1B+gPPjbjINdufl0UXqyYplE0aGhx8=
github.com/moloch--/memmod v0.0.0-20211120144554-8b37cc654945/go.mod h1:1grVt4HaTofvhFUZYtofeRbGXfczNwCie9MYoM4lP/o=
github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde h1:x0TT0RDC7UhAVbbWWBzr41ElhJx5tXPWkIHA2HWPRuw=
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/pkg/profile v1.6.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@@ -326,18 +269,11 @@ github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/shirou/gopsutil/v3 v3.22.11 h1:kxsPKS+Eeo+VnEQ2XCaGJepeP6KY53QoRTETx3+1ndM=
github.com/shirou/gopsutil/v3 v3.22.11/go.mod h1:xl0EeL4vXJ+hQMAGN8B9VFpxukEMA0XdevQOe5MZ1oY=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/shirou/gopsutil/v3 v3.22.12 h1:oG0ns6poeUSxf78JtOsfygNWuEHYYz8hnnNg7P04TJs=
github.com/shirou/gopsutil/v3 v3.22.12/go.mod h1:Xd7P1kwZcp5VW52+9XsirIKd/BROzbb2wdX3Kqlz9uI=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
@@ -348,7 +284,6 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
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.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
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/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
@@ -378,46 +313,32 @@ github.com/yiya1989/sshkrb5 v0.0.0-20201110125252-a1455b75a35e/go.mod h1:r1bHcNa
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/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-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/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.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220208050332-20e1d8d225ab/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM=
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8=
golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80=
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/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
@@ -431,7 +352,6 @@ golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73r
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-20190813141303-74dc4d7220e7/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-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
@@ -443,8 +363,9 @@ golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/go.mod h1:9nx3DQGgdP8bBQD5qx
golang.org/x/net v0.0.0-20211111083644-e5c967477495/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.3.0 h1:VWL6FNY2bEEmsGVKabSlHu5Irp34xmMRoqb/9lF9lxk=
golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1 h1:B333XXssMuKQeBwiNODx4TupZy7bf4sxFZnN2ZOcvUE=
@@ -455,17 +376,16 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
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.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7 h1:ZrnxWX62AgTKOSagEqxvb3ffipvEDX2pl7E1TdqLqIc=
golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180606202747-9527bec2660b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
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-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-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
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-20190530182044-ad28b68e88f1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -494,23 +414,24 @@ golang.org/x/sys v0.0.0-20220207234003-57398862261d/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220330033206-e17cdc41300f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI=
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE=
@@ -519,14 +440,8 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
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-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
@@ -534,8 +449,6 @@ golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
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=
@@ -587,10 +500,9 @@ gopkg.in/AlecAivazis/survey.v1 v1.8.8 h1:5UtTowJZTz1j7NxVzDGKTz6Lm9IWm8DDF6b7a2w
gopkg.in/AlecAivazis/survey.v1 v1.8.8/go.mod h1:CaHjv79TCgAvXMSFJSVgonHXYWxnhzI3eoHtnX5UgUo=
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-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U=
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/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/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
gopkg.in/jcmturner/aescts.v1 v1.0.1 h1:cVVZBK2b1zY26haWB4vbBiZrfFQnfbTVrE3xZq6hrEw=
gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo=
gopkg.in/jcmturner/dnsutils.v1 v1.0.1 h1:cIuC1OLRGZrld+16ZJvvZxVJeKPsvd5eUIvxfoN5hSM=
@@ -608,19 +520,18 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/mysql v1.4.4 h1:MX0K9Qvy0Na4o7qSC/YI7XxqUw5KDw01umqgID+svdQ=
gorm.io/driver/mysql v1.4.4/go.mod h1:BCg8cKI+R0j/rZRQxeKis/forqRwRSYOR8OM3Wo6hOM=
gorm.io/driver/postgres v1.4.5 h1:mTeXTTtHAgnS9PgmhN2YeUbazYpLhUI1doLnw42XUZc=
gorm.io/driver/postgres v1.4.5/go.mod h1:GKNQYSJ14qvWkvPwXljMGehpKrhlDNsqYRr5HnYGncg=
gorm.io/driver/postgres v1.4.6 h1:1FPESNXqIKG5JmraaH2bfCVlMQ7paLoCreFxDtqzwdc=
gorm.io/driver/postgres v1.4.6/go.mod h1:UJChCNLFKeBqQRE+HrkFUbKbq9idPXmTOk2u4Wok8S4=
gorm.io/driver/sqlite v1.4.4 h1:gIufGoR0dQzjkyqDyYSCvsYR6fba1Gw5YKDqKeChxFc=
gorm.io/driver/sqlite v1.4.4/go.mod h1:0Aq3iPO+v9ZKbcdiz8gLWRw5VOPcBOPUQJFLq5e2ecI=
gorm.io/gorm v1.23.8/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk=
gorm.io/gorm v1.24.0/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA=
gorm.io/gorm v1.24.1-0.20221019064659-5dd2bb482755 h1:7AdrbfcvKnzejfqP5g37fdSZOXH/JvaPIzBIHTOqXKk=
gorm.io/gorm v1.24.1-0.20221019064659-5dd2bb482755/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA=
gorm.io/gorm v1.24.2 h1:9wR6CFD+G8nOusLdvkZelOEhpJVwwHzpQOUM+REd6U0=
gorm.io/gorm v1.24.2/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA=
gvisor.dev/gvisor v0.0.0-20220817001344-846276b3dbc5 h1:cv/zaNV0nr1mJzaeo4S5mHIm5va1W0/9J3/5prlsuRM=
gvisor.dev/gvisor v0.0.0-20220817001344-846276b3dbc5/go.mod h1:TIvkJD0sxe8pIob3p6T8IzxXunlp6yfgktvTNp+DGNM=
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=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI=
lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
modernc.org/cc/v3 v3.40.0 h1:P3g79IUS/93SYhtoeaHW+kRCIrYaxJ27MFPv+7kaTOw=
+19 -19
View File
@@ -20,7 +20,6 @@ package cryptography
import (
"bytes"
"compress/gzip"
"crypto/rand"
"crypto/sha256"
"crypto/x509"
@@ -35,6 +34,7 @@ import (
"log"
// {{end}}
"github.com/bishopfox/sliver/implant/sliver/encoders"
"github.com/pquerna/otp"
"github.com/pquerna/otp/totp"
"golang.org/x/crypto/chacha20poly1305"
@@ -107,7 +107,7 @@ func Encrypt(key [chacha20poly1305.KeySize]byte, plaintext []byte) ([]byte, erro
if err != nil {
return nil, err
}
plaintext = bytes.NewBuffer(GzipBuf(plaintext)).Bytes()
plaintext = bytes.NewBuffer(encoders.GzipBuf(plaintext)).Bytes()
nonce := make([]byte, aead.NonceSize(), aead.NonceSize()+len(plaintext)+aead.Overhead())
if _, err := rand.Read(nonce); err != nil {
return nil, err
@@ -134,7 +134,7 @@ func Decrypt(key [chacha20poly1305.KeySize]byte, ciphertext []byte) ([]byte, err
if err != nil {
return nil, err
}
return GunzipBuf(plaintext), nil
return encoders.GunzipBuf(plaintext), nil
}
// NewCipherContext - Wrapper around creating a cipher context from a key
@@ -248,19 +248,19 @@ func RootOnlyVerifyCertificate(caCertPEM string, rawCerts [][]byte, _ [][]*x509.
return nil
}
// GzipBuf - Gzip a buffer
func GzipBuf(data []byte) []byte {
var buf bytes.Buffer
zip := gzip.NewWriter(&buf)
zip.Write(data)
zip.Close()
return buf.Bytes()
}
// GunzipBuf - Gunzip a buffer
func GunzipBuf(data []byte) []byte {
zip, _ := gzip.NewReader(bytes.NewBuffer(data))
var buf bytes.Buffer
buf.ReadFrom(zip)
return buf.Bytes()
}
//// GzipBuf - Gzip a buffer
//func GzipBuf(data []byte) []byte {
// var buf bytes.Buffer
// zip := gzip.NewWriter(&buf)
// zip.Write(data)
// zip.Close()
// return buf.Bytes()
//}
//
//// GunzipBuf - Gunzip a buffer
//func GunzipBuf(data []byte) []byte {
// zip, _ := gzip.NewReader(bytes.NewBuffer(data))
// var buf bytes.Buffer
// buf.ReadFrom(zip)
// return buf.Bytes()
//}
+34 -1
View File
@@ -21,6 +21,7 @@ package encoders
import (
"bytes"
"compress/gzip"
"sync"
)
// GzipEncoderID - EncoderID
@@ -29,12 +30,44 @@ const GzipEncoderID = 49
// Gzip - Gzip compression encoder
type Gzip struct{}
var gzipWriterPools = &sync.Pool{}
func init() {
gzipWriterPools = &sync.Pool{
New: func() interface{} {
w, _ := gzip.NewWriterLevel(nil, gzip.BestSpeed)
return w
},
}
}
// GzipBuf - Gzip a buffer
func GzipBuf(data []byte) []byte {
var buf bytes.Buffer
gzipWriter := gzipWriterPools.Get().(*gzip.Writer)
gzipWriter.Reset(&buf)
gzipWriter.Write(data)
gzipWriter.Close()
gzipWriterPools.Put(gzipWriter)
return buf.Bytes()
}
// GunzipBuf - Gunzip a buffer
func GunzipBuf(data []byte) []byte {
zip, _ := gzip.NewReader(bytes.NewBuffer(data))
var buf bytes.Buffer
buf.ReadFrom(zip)
return buf.Bytes()
}
// Encode - Compress data with gzip
func (g Gzip) Encode(data []byte) []byte {
var buf bytes.Buffer
gzipWriter, _ := gzip.NewWriterLevel(&buf, gzip.BestSpeed)
gzipWriter := gzipWriterPools.Get().(*gzip.Writer)
gzipWriter.Reset(&buf)
gzipWriter.Write(data)
gzipWriter.Close()
gzipWriterPools.Put(gzipWriter)
return buf.Bytes()
}
+1
View File
@@ -1220,6 +1220,7 @@ type ImplantConfig struct {
Evasion bool `protobuf:"varint,9,opt,name=Evasion,proto3" json:"Evasion,omitempty"`
ObfuscateSymbols bool `protobuf:"varint,10,opt,name=ObfuscateSymbols,proto3" json:"ObfuscateSymbols,omitempty"`
TemplateName string `protobuf:"bytes,11,opt,name=TemplateName,proto3" json:"TemplateName,omitempty"`
DisableSGN bool `protobuf:"varint,12,opt,name=DisableSGN,proto3" json:"DisableSGN,omitempty"`
MtlsCACert string `protobuf:"bytes,20,opt,name=MtlsCACert,proto3" json:"MtlsCACert,omitempty"`
MtlsCert string `protobuf:"bytes,21,opt,name=MtlsCert,proto3" json:"MtlsCert,omitempty"`
MtlsKey string `protobuf:"bytes,22,opt,name=MtlsKey,proto3" json:"MtlsKey,omitempty"`
+3 -3
View File
@@ -37,7 +37,7 @@ import (
"github.com/bishopfox/sliver/server/cryptography/minisign"
"github.com/bishopfox/sliver/server/db"
"github.com/bishopfox/sliver/util"
"github.com/bishopfox/sliver/util/encoders"
"github.com/pquerna/otp"
"github.com/pquerna/otp/totp"
"golang.org/x/crypto/chacha20poly1305"
@@ -146,7 +146,7 @@ func Encrypt(key [chacha20poly1305.KeySize]byte, plaintext []byte) ([]byte, erro
if err != nil {
return nil, err
}
plaintext = bytes.NewBuffer(util.GzipBuf(plaintext)).Bytes()
plaintext = bytes.NewBuffer(encoders.GzipBuf(plaintext)).Bytes()
nonce := make([]byte, aead.NonceSize(), aead.NonceSize()+len(plaintext)+aead.Overhead())
if _, err := rand.Read(nonce); err != nil {
return nil, err
@@ -173,7 +173,7 @@ func Decrypt(key [chacha20poly1305.KeySize]byte, ciphertext []byte) ([]byte, err
if err != nil {
return nil, err
}
return util.GunzipBuf(plaintext), nil
return encoders.GunzipBuf(plaintext), nil
}
// NewCipherContext - Wrapper around creating a cipher context from a key
+3 -2
View File
@@ -55,7 +55,7 @@ func EncoderFromNonce(nonce int) (int, Encoder, error) {
if encoder, ok := EncoderMap[encoderID]; ok {
return encoderID, encoder, nil
}
return -1, nil, errors.New("Invalid encoder nonce")
return -1, nil, errors.New("invalid encoder nonce")
}
// RandomEncoder - Get a random nonce identifier and a matching encoder
@@ -70,7 +70,8 @@ func RandomEncoder() (int, Encoder) {
}
// NopNonce - A NOP nonce identifies a request with no encoder/payload
// any value where mod = 0
//
// any value where mod = 0
func NopNonce() int {
return insecureRand.Intn(maxN) * EncoderModulus
}
+34 -2
View File
@@ -21,6 +21,7 @@ package encoders
import (
"bytes"
"compress/gzip"
"sync"
)
// GzipEncoderID - EncoderID
@@ -29,18 +30,49 @@ const GzipEncoderID = 49
// Gzip - Gzip compression encoder
type Gzip struct{}
var gzipWriterPools = &sync.Pool{}
func init() {
gzipWriterPools = &sync.Pool{
New: func() interface{} {
w, _ := gzip.NewWriterLevel(nil, gzip.BestSpeed)
return w
},
}
}
// GzipBuf - Gzip a buffer
func GzipBuf(data []byte) []byte {
var buf bytes.Buffer
gzipWriter := gzipWriterPools.Get().(*gzip.Writer)
gzipWriter.Reset(&buf)
gzipWriter.Write(data)
gzipWriter.Close()
gzipWriterPools.Put(gzipWriter)
return buf.Bytes()
}
// GunzipBuf - Gunzip a buffer
func GunzipBuf(data []byte) []byte {
zip, _ := gzip.NewReader(bytes.NewBuffer(data))
var buf bytes.Buffer
buf.ReadFrom(zip)
return buf.Bytes()
}
// Encode - Compress data with gzip
func (g Gzip) Encode(data []byte) []byte {
var buf bytes.Buffer
gzipWriter, _ := gzip.NewWriterLevel(&buf, gzip.BestSpeed)
gzipWriter := gzipWriterPools.Get().(*gzip.Writer)
gzipWriter.Reset(&buf)
gzipWriter.Write(data)
gzipWriter.Close()
gzipWriterPools.Put(gzipWriter)
return buf.Bytes()
}
// Decode - Uncompressed data with gzip
func (g Gzip) Decode(data []byte) ([]byte, error) {
bytes.NewReader(data)
reader, err := gzip.NewReader(bytes.NewReader(data))
if err != nil {
return nil, err
+26 -7
View File
@@ -1,12 +1,5 @@
package encoders
import (
"bytes"
"testing"
implantEncoders "github.com/bishopfox/sliver/implant/sliver/encoders"
)
/*
Sliver Implant Framework
Copyright (C) 2019 Bishop Fox
@@ -25,6 +18,15 @@ import (
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"bytes"
"crypto/rand"
insecureRand "math/rand"
"testing"
implantEncoders "github.com/bishopfox/sliver/implant/sliver/encoders"
)
func TestGzip(t *testing.T) {
sample := randomData()
@@ -60,3 +62,20 @@ func TestGzip(t *testing.T) {
t.Errorf("server/implant outputs do not match returned\n%#v != %#v", sample, data)
}
}
func randomDataRandomSize(maxSize int) []byte {
buf := make([]byte, insecureRand.Intn(maxSize))
rand.Read(buf)
return buf
}
func TestGzipGunzip(t *testing.T) {
for i := 0; i < 100; i++ {
data := randomDataRandomSize(8192)
gzipData := GzipBuf(data)
gunzipData := GunzipBuf(gzipData)
if !bytes.Equal(data, gunzipData) {
t.Fatalf("Data does not match")
}
}
}
+9 -9
View File
@@ -1,12 +1,5 @@
package encoders
import (
"bytes"
"testing"
implantEncoders "github.com/bishopfox/sliver/implant/sliver/encoders"
)
/*
Sliver Implant Framework
Copyright (C) 2019 Bishop Fox
@@ -25,6 +18,13 @@ import (
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import (
"bytes"
"testing"
implantEncoders "github.com/bishopfox/sliver/implant/sliver/encoders"
)
func TestHex(t *testing.T) {
sample := randomData()
@@ -51,8 +51,8 @@ func TestHex(t *testing.T) {
}
// Interoperability
if bytes.Compare(output, output2) != 0 {
t.Errorf("impant encoder does not match server-side encoder %s", err)
if !bytes.Equal(output, output2) {
t.Errorf("implant encoder does not match server-side encoder %s", err)
}
data3, err := implantHex.Decode(output)
-17
View File
@@ -30,23 +30,6 @@ import (
"path/filepath"
)
// GzipBuf - Gzip a buffer
func GzipBuf(data []byte) []byte {
var buf bytes.Buffer
zip := gzip.NewWriter(&buf)
zip.Write(data)
zip.Close()
return buf.Bytes()
}
// GunzipBuf - Gunzip a buffer
func GunzipBuf(data []byte) []byte {
zip, _ := gzip.NewReader(bytes.NewBuffer(data))
var buf bytes.Buffer
buf.ReadFrom(zip)
return buf.Bytes()
}
// DeflateBuf - Deflate a buffer using BestCompression (9)
func DeflateBuf(data []byte) []byte {
var buf bytes.Buffer
-13
View File
@@ -19,10 +19,8 @@ package util
*/
import (
"bytes"
"crypto/rand"
insecureRand "math/rand"
"testing"
)
func randomDataRandomSize(maxSize int) []byte {
@@ -30,14 +28,3 @@ func randomDataRandomSize(maxSize int) []byte {
rand.Read(buf)
return buf
}
func TestGzipGunzip(t *testing.T) {
for i := 0; i < 100; i++ {
data := randomDataRandomSize(8192)
gzipData := GzipBuf(data)
gunzipData := GunzipBuf(gzipData)
if !bytes.Equal(data, gunzipData) {
t.Fatalf("Data does not match")
}
}
}
-9
View File
@@ -1,9 +0,0 @@
language: go
go:
- 1.x
- tip
matrix:
allow_failures:
- go: tip
-22
View File
@@ -1,22 +0,0 @@
Copyright (c) 2019 Jack Christensen
MIT License
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-8
View File
@@ -1,8 +0,0 @@
[![](https://godoc.org/github.com/jackc/chunkreader?status.svg)](https://godoc.org/github.com/jackc/chunkreader)
[![Build Status](https://travis-ci.org/jackc/chunkreader.svg)](https://travis-ci.org/jackc/chunkreader)
# chunkreader
Package chunkreader provides an io.Reader wrapper that minimizes IO reads and memory allocations.
Extracted from original implementation in https://github.com/jackc/pgx.
-104
View File
@@ -1,104 +0,0 @@
// Package chunkreader provides an io.Reader wrapper that minimizes IO reads and memory allocations.
package chunkreader
import (
"io"
)
// ChunkReader is a io.Reader wrapper that minimizes IO reads and memory allocations. It allocates memory in chunks and
// will read as much as will fit in the current buffer in a single call regardless of how large a read is actually
// requested. The memory returned via Next is owned by the caller. This avoids the need for an additional copy.
//
// The downside of this approach is that a large buffer can be pinned in memory even if only a small slice is
// referenced. For example, an entire 4096 byte block could be pinned in memory by even a 1 byte slice. In these rare
// cases it would be advantageous to copy the bytes to another slice.
type ChunkReader struct {
r io.Reader
buf []byte
rp, wp int // buf read position and write position
config Config
}
// Config contains configuration parameters for ChunkReader.
type Config struct {
MinBufLen int // Minimum buffer length
}
// New creates and returns a new ChunkReader for r with default configuration.
func New(r io.Reader) *ChunkReader {
cr, err := NewConfig(r, Config{})
if err != nil {
panic("default config can't be bad")
}
return cr
}
// NewConfig creates and a new ChunkReader for r configured by config.
func NewConfig(r io.Reader, config Config) (*ChunkReader, error) {
if config.MinBufLen == 0 {
// By historical reasons Postgres currently has 8KB send buffer inside,
// so here we want to have at least the same size buffer.
// @see https://github.com/postgres/postgres/blob/249d64999615802752940e017ee5166e726bc7cd/src/backend/libpq/pqcomm.c#L134
// @see https://www.postgresql.org/message-id/0cdc5485-cb3c-5e16-4a46-e3b2f7a41322%40ya.ru
config.MinBufLen = 8192
}
return &ChunkReader{
r: r,
buf: make([]byte, config.MinBufLen),
config: config,
}, nil
}
// Next returns buf filled with the next n bytes. The caller gains ownership of buf. It is not necessary to make a copy
// of buf. If an error occurs, buf will be nil.
func (r *ChunkReader) Next(n int) (buf []byte, err error) {
// n bytes already in buf
if (r.wp - r.rp) >= n {
buf = r.buf[r.rp : r.rp+n]
r.rp += n
return buf, err
}
// available space in buf is less than n
if len(r.buf) < n {
r.copyBufContents(r.newBuf(n))
}
// buf is large enough, but need to shift filled area to start to make enough contiguous space
minReadCount := n - (r.wp - r.rp)
if (len(r.buf) - r.wp) < minReadCount {
newBuf := r.newBuf(n)
r.copyBufContents(newBuf)
}
if err := r.appendAtLeast(minReadCount); err != nil {
return nil, err
}
buf = r.buf[r.rp : r.rp+n]
r.rp += n
return buf, nil
}
func (r *ChunkReader) appendAtLeast(fillLen int) error {
n, err := io.ReadAtLeast(r.r, r.buf[r.wp:], fillLen)
r.wp += n
return err
}
func (r *ChunkReader) newBuf(size int) []byte {
if size < r.config.MinBufLen {
size = r.config.MinBufLen
}
return make([]byte, size)
}
func (r *ChunkReader) copyBufContents(dest []byte) {
r.wp = copy(dest, r.buf[r.rp:r.wp])
r.rp = 0
r.buf = dest
}
-3
View File
@@ -1,3 +0,0 @@
.envrc
vendor/
.vscode
-154
View File
@@ -1,154 +0,0 @@
# 1.13.0 (August 6, 2022)
* Add sslpassword support (Eric McCormack and yun.xu)
* Add prefer-standby target_session_attrs support (sergey.bashilov)
* Fix GSS ErrorResponse handling (Oliver Tan)
# 1.12.1 (May 7, 2022)
* Fix: setting krbspn and krbsrvname in connection string (sireax)
* Add support for Unix sockets on Windows (Eno Compton)
* Stop ignoring ErrorResponse during SCRAM auth (Rafi Shamim)
# 1.12.0 (April 21, 2022)
* Add pluggable GSSAPI support (Oliver Tan)
* Fix: Consider any "0A000" error a possible cached plan changed error due to locale
* Better match psql fallback behavior with multiple hosts
# 1.11.0 (February 7, 2022)
* Support port in ip from LookupFunc to override config (James Hartig)
* Fix TLS connection timeout (Blake Embrey)
* Add support for read-only, primary, standby, prefer-standby target_session_attributes (Oscar)
* Fix connect when receiving NoticeResponse
# 1.10.1 (November 20, 2021)
* Close without waiting for response (Kei Kamikawa)
* Save waiting for network round-trip in CopyFrom (Rueian)
* Fix concurrency issue with ContextWatcher
* LRU.Get always checks context for cancellation / expiration (Georges Varouchas)
# 1.10.0 (July 24, 2021)
* net.Timeout errors are no longer returned when a query is canceled via context. A wrapped context error is returned.
# 1.9.0 (July 10, 2021)
* pgconn.Timeout only is true for errors originating in pgconn (Michael Darr)
* Add defaults for sslcert, sslkey, and sslrootcert (Joshua Brindle)
* Solve issue with 'sslmode=verify-full' when there are multiple hosts (mgoddard)
* Fix default host when parsing URL without host but with port
* Allow dbname query parameter in URL conn string
* Update underlying dependencies
# 1.8.1 (March 25, 2021)
* Better connection string sanitization (ip.novikov)
* Use proper pgpass location on Windows (Moshe Katz)
* Use errors instead of golang.org/x/xerrors
* Resume fallback on server error in Connect (Andrey Borodin)
# 1.8.0 (December 3, 2020)
* Add StatementErrored method to stmtcache.Cache. This allows the cache to purge invalidated prepared statements. (Ethan Pailes)
# 1.7.2 (November 3, 2020)
* Fix data value slices into work buffer with capacities larger than length.
# 1.7.1 (October 31, 2020)
* Do not asyncClose after receiving FATAL error from PostgreSQL server
# 1.7.0 (September 26, 2020)
* Exec(Params|Prepared) return ResultReader with FieldDescriptions loaded
* Add ReceiveResults (Sebastiaan Mannem)
* Fix parsing DSN connection with bad backslash
* Add PgConn.CleanupDone so connection pools can determine when async close is complete
# 1.6.4 (July 29, 2020)
* Fix deadlock on error after CommandComplete but before ReadyForQuery
* Fix panic on parsing DSN with trailing '='
# 1.6.3 (July 22, 2020)
* Fix error message after AppendCertsFromPEM failure (vahid-sohrabloo)
# 1.6.2 (July 14, 2020)
* Update pgservicefile library
# 1.6.1 (June 27, 2020)
* Update golang.org/x/crypto to latest
* Update golang.org/x/text to 0.3.3
* Fix error handling for bad PGSERVICE definition
* Redact passwords in ParseConfig errors (Lukas Vogel)
# 1.6.0 (June 6, 2020)
* Fix panic when closing conn during cancellable query
* Fix behavior of sslmode=require with sslrootcert present (Petr Jediný)
* Fix field descriptions available after command concluded (Tobias Salzmann)
* Support connect_timeout (georgysavva)
* Handle IPv6 in connection URLs (Lukas Vogel)
* Fix ValidateConnect with cancelable context
* Improve CopyFrom performance
* Add Config.Copy (georgysavva)
# 1.5.0 (March 30, 2020)
* Update golang.org/x/crypto for security fix
* Implement "verify-ca" SSL mode (Greg Curtis)
# 1.4.0 (March 7, 2020)
* Fix ExecParams and ExecPrepared handling of empty query.
* Support reading config from PostgreSQL service files.
# 1.3.2 (February 14, 2020)
* Update chunkreader to v2.0.1 for optimized default buffer size.
# 1.3.1 (February 5, 2020)
* Fix CopyFrom deadlock when multiple NoticeResponse received during copy
# 1.3.0 (January 23, 2020)
* Add Hijack and Construct.
* Update pgproto3 to v2.0.1.
# 1.2.1 (January 13, 2020)
* Fix data race in context cancellation introduced in v1.2.0.
# 1.2.0 (January 11, 2020)
## Features
* Add Insert(), Update(), Delete(), and Select() statement type query methods to CommandTag.
* Add PgError.SQLState method. This could be used for compatibility with other drivers and databases.
## Performance
* Improve performance when context.Background() is used. (bakape)
* CommandTag.RowsAffected is faster and does not allocate.
## Fixes
* Try to cancel any in-progress query when a conn is closed by ctx cancel.
* Handle NoticeResponse during CopyFrom.
* Ignore errors sending Terminate message while closing connection. This mimics the behavior of libpq PGfinish.
# 1.1.0 (October 12, 2019)
* Add PgConn.IsBusy() method.
# 1.0.1 (September 19, 2019)
* Fix statement cache not properly cleaning discarded statements.
-22
View File
@@ -1,22 +0,0 @@
Copyright (c) 2019-2021 Jack Christensen
MIT License
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-56
View File
@@ -1,56 +0,0 @@
[![](https://godoc.org/github.com/jackc/pgconn?status.svg)](https://godoc.org/github.com/jackc/pgconn)
![CI](https://github.com/jackc/pgconn/workflows/CI/badge.svg)
# pgconn
Package pgconn is a low-level PostgreSQL database driver. It operates at nearly the same level as the C library libpq.
It is primarily intended to serve as the foundation for higher level libraries such as https://github.com/jackc/pgx.
Applications should handle normal queries with a higher level library and only use pgconn directly when required for
low-level access to PostgreSQL functionality.
## Example Usage
```go
pgConn, err := pgconn.Connect(context.Background(), os.Getenv("DATABASE_URL"))
if err != nil {
log.Fatalln("pgconn failed to connect:", err)
}
defer pgConn.Close(context.Background())
result := pgConn.ExecParams(context.Background(), "SELECT email FROM users WHERE id=$1", [][]byte{[]byte("123")}, nil, nil, nil)
for result.NextRow() {
fmt.Println("User 123 has email:", string(result.Values()[0]))
}
_, err = result.Close()
if err != nil {
log.Fatalln("failed reading result:", err)
}
```
## Testing
The pgconn tests require a PostgreSQL database. It will connect to the database specified in the `PGX_TEST_CONN_STRING`
environment variable. The `PGX_TEST_CONN_STRING` environment variable can be a URL or DSN. In addition, the standard `PG*`
environment variables will be respected. Consider using [direnv](https://github.com/direnv/direnv) to simplify
environment variable handling.
### Example Test Environment
Connect to your PostgreSQL server and run:
```
create database pgx_test;
```
Now you can run the tests:
```bash
PGX_TEST_CONN_STRING="host=/var/run/postgresql dbname=pgx_test" go test ./...
```
### Connection and Authentication Tests
Pgconn supports multiple connection types and means of authentication. These tests are optional. They
will only run if the appropriate environment variable is set. Run `go test -v | grep SKIP` to see if any tests are being
skipped. Most developers will not need to enable these tests. See `ci/setup_test.bash` for an example set up if you need change
authentication code.
-169
View File
@@ -1,169 +0,0 @@
package stmtcache
import (
"container/list"
"context"
"fmt"
"sync/atomic"
"github.com/jackc/pgconn"
)
var lruCount uint64
// LRU implements Cache with a Least Recently Used (LRU) cache.
type LRU struct {
conn *pgconn.PgConn
mode int
cap int
prepareCount int
m map[string]*list.Element
l *list.List
psNamePrefix string
stmtsToClear []string
}
// NewLRU creates a new LRU. mode is either ModePrepare or ModeDescribe. cap is the maximum size of the cache.
func NewLRU(conn *pgconn.PgConn, mode int, cap int) *LRU {
mustBeValidMode(mode)
mustBeValidCap(cap)
n := atomic.AddUint64(&lruCount, 1)
return &LRU{
conn: conn,
mode: mode,
cap: cap,
m: make(map[string]*list.Element),
l: list.New(),
psNamePrefix: fmt.Sprintf("lrupsc_%d", n),
}
}
// Get returns the prepared statement description for sql preparing or describing the sql on the server as needed.
func (c *LRU) Get(ctx context.Context, sql string) (*pgconn.StatementDescription, error) {
if ctx != context.Background() {
select {
case <-ctx.Done():
return nil, ctx.Err()
default:
}
}
// flush an outstanding bad statements
txStatus := c.conn.TxStatus()
if (txStatus == 'I' || txStatus == 'T') && len(c.stmtsToClear) > 0 {
for _, stmt := range c.stmtsToClear {
err := c.clearStmt(ctx, stmt)
if err != nil {
return nil, err
}
}
}
if el, ok := c.m[sql]; ok {
c.l.MoveToFront(el)
return el.Value.(*pgconn.StatementDescription), nil
}
if c.l.Len() == c.cap {
err := c.removeOldest(ctx)
if err != nil {
return nil, err
}
}
psd, err := c.prepare(ctx, sql)
if err != nil {
return nil, err
}
el := c.l.PushFront(psd)
c.m[sql] = el
return psd, nil
}
// Clear removes all entries in the cache. Any prepared statements will be deallocated from the PostgreSQL session.
func (c *LRU) Clear(ctx context.Context) error {
for c.l.Len() > 0 {
err := c.removeOldest(ctx)
if err != nil {
return err
}
}
return nil
}
func (c *LRU) StatementErrored(sql string, err error) {
pgErr, ok := err.(*pgconn.PgError)
if !ok {
return
}
// https://github.com/jackc/pgx/issues/1162
//
// We used to look for the message "cached plan must not change result type". However, that message can be localized.
// Unfortunately, error code "0A000" - "FEATURE NOT SUPPORTED" is used for many different errors and the only way to
// tell the difference is by the message. But all that happens is we clear a statement that we otherwise wouldn't
// have so it should be safe.
possibleInvalidCachedPlanError := pgErr.Code == "0A000"
if possibleInvalidCachedPlanError {
c.stmtsToClear = append(c.stmtsToClear, sql)
}
}
func (c *LRU) clearStmt(ctx context.Context, sql string) error {
elem, inMap := c.m[sql]
if !inMap {
// The statement probably fell off the back of the list. In that case, we've
// ensured that it isn't in the cache, so we can declare victory.
return nil
}
c.l.Remove(elem)
psd := elem.Value.(*pgconn.StatementDescription)
delete(c.m, psd.SQL)
if c.mode == ModePrepare {
return c.conn.Exec(ctx, fmt.Sprintf("deallocate %s", psd.Name)).Close()
}
return nil
}
// Len returns the number of cached prepared statement descriptions.
func (c *LRU) Len() int {
return c.l.Len()
}
// Cap returns the maximum number of cached prepared statement descriptions.
func (c *LRU) Cap() int {
return c.cap
}
// Mode returns the mode of the cache (ModePrepare or ModeDescribe)
func (c *LRU) Mode() int {
return c.mode
}
func (c *LRU) prepare(ctx context.Context, sql string) (*pgconn.StatementDescription, error) {
var name string
if c.mode == ModePrepare {
name = fmt.Sprintf("%s_%d", c.psNamePrefix, c.prepareCount)
c.prepareCount += 1
}
return c.conn.Prepare(ctx, name, sql, nil)
}
func (c *LRU) removeOldest(ctx context.Context) error {
oldest := c.l.Back()
c.l.Remove(oldest)
psd := oldest.Value.(*pgconn.StatementDescription)
delete(c.m, psd.SQL)
if c.mode == ModePrepare {
return c.conn.Exec(ctx, fmt.Sprintf("deallocate %s", psd.Name)).Close()
}
return nil
}
-58
View File
@@ -1,58 +0,0 @@
// Package stmtcache is a cache that can be used to implement lazy prepared statements.
package stmtcache
import (
"context"
"github.com/jackc/pgconn"
)
const (
ModePrepare = iota // Cache should prepare named statements.
ModeDescribe // Cache should prepare the anonymous prepared statement to only fetch the description of the statement.
)
// Cache prepares and caches prepared statement descriptions.
type Cache interface {
// Get returns the prepared statement description for sql preparing or describing the sql on the server as needed.
Get(ctx context.Context, sql string) (*pgconn.StatementDescription, error)
// Clear removes all entries in the cache. Any prepared statements will be deallocated from the PostgreSQL session.
Clear(ctx context.Context) error
// StatementErrored informs the cache that the given statement resulted in an error when it
// was last used against the database. In some cases, this will cause the cache to maer that
// statement as bad. The bad statement will instead be flushed during the next call to Get
// that occurs outside of a failed transaction.
StatementErrored(sql string, err error)
// Len returns the number of cached prepared statement descriptions.
Len() int
// Cap returns the maximum number of cached prepared statement descriptions.
Cap() int
// Mode returns the mode of the cache (ModePrepare or ModeDescribe)
Mode() int
}
// New returns the preferred cache implementation for mode and cap. mode is either ModePrepare or ModeDescribe. cap is
// the maximum size of the cache.
func New(conn *pgconn.PgConn, mode int, cap int) Cache {
mustBeValidMode(mode)
mustBeValidCap(cap)
return NewLRU(conn, mode, cap)
}
func mustBeValidMode(mode int) {
if mode != ModePrepare && mode != ModeDescribe {
panic("mode must be ModePrepare or ModeDescribe")
}
}
func mustBeValidCap(cap int) {
if cap < 1 {
panic("cache must have cap of >= 1")
}
}
-9
View File
@@ -1,9 +0,0 @@
language: go
go:
- 1.x
- tip
matrix:
allow_failures:
- go: tip
-22
View File
@@ -1,22 +0,0 @@
Copyright (c) 2019 Jack Christensen
MIT License
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-11
View File
@@ -1,11 +0,0 @@
[![](https://godoc.org/github.com/jackc/pgio?status.svg)](https://godoc.org/github.com/jackc/pgio)
[![Build Status](https://travis-ci.org/jackc/pgio.svg)](https://travis-ci.org/jackc/pgio)
# pgio
Package pgio is a low-level toolkit building messages in the PostgreSQL wire protocol.
pgio provides functions for appending integers to a []byte while doing byte
order conversion.
Extracted from original implementation in https://github.com/jackc/pgx.
-9
View File
@@ -1,9 +0,0 @@
language: go
go:
- 1.x
- tip
matrix:
allow_failures:
- go: tip
-22
View File
@@ -1,22 +0,0 @@
Copyright (c) 2019 Jack Christensen
MIT License
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-19
View File
@@ -1,19 +0,0 @@
package pgproto3
import (
"io"
"github.com/jackc/chunkreader/v2"
)
// ChunkReader is an interface to decouple github.com/jackc/chunkreader from this package.
type ChunkReader interface {
// Next returns buf filled with the next n bytes. If an error (including a partial read) occurs,
// buf must be nil. Next must preserve any partially read data. Next must not reuse buf.
Next(n int) (buf []byte, err error)
}
// NewChunkReader creates and returns a new default ChunkReader.
func NewChunkReader(r io.Reader) ChunkReader {
return chunkreader.New(r)
}
-4
View File
@@ -1,4 +0,0 @@
// Package pgproto3 is a encoder and decoder of the PostgreSQL wire protocol version 3.
//
// See https://www.postgresql.org/docs/current/protocol-message-formats.html for meanings of the different messages.
package pgproto3
-206
View File
@@ -1,206 +0,0 @@
package pgproto3
import (
"encoding/binary"
"errors"
"fmt"
"io"
)
// Frontend acts as a client for the PostgreSQL wire protocol version 3.
type Frontend struct {
cr ChunkReader
w io.Writer
// Backend message flyweights
authenticationOk AuthenticationOk
authenticationCleartextPassword AuthenticationCleartextPassword
authenticationMD5Password AuthenticationMD5Password
authenticationGSS AuthenticationGSS
authenticationGSSContinue AuthenticationGSSContinue
authenticationSASL AuthenticationSASL
authenticationSASLContinue AuthenticationSASLContinue
authenticationSASLFinal AuthenticationSASLFinal
backendKeyData BackendKeyData
bindComplete BindComplete
closeComplete CloseComplete
commandComplete CommandComplete
copyBothResponse CopyBothResponse
copyData CopyData
copyInResponse CopyInResponse
copyOutResponse CopyOutResponse
copyDone CopyDone
dataRow DataRow
emptyQueryResponse EmptyQueryResponse
errorResponse ErrorResponse
functionCallResponse FunctionCallResponse
noData NoData
noticeResponse NoticeResponse
notificationResponse NotificationResponse
parameterDescription ParameterDescription
parameterStatus ParameterStatus
parseComplete ParseComplete
readyForQuery ReadyForQuery
rowDescription RowDescription
portalSuspended PortalSuspended
bodyLen int
msgType byte
partialMsg bool
authType uint32
}
// NewFrontend creates a new Frontend.
func NewFrontend(cr ChunkReader, w io.Writer) *Frontend {
return &Frontend{cr: cr, w: w}
}
// Send sends a message to the backend.
func (f *Frontend) Send(msg FrontendMessage) error {
_, err := f.w.Write(msg.Encode(nil))
return err
}
func translateEOFtoErrUnexpectedEOF(err error) error {
if err == io.EOF {
return io.ErrUnexpectedEOF
}
return err
}
// Receive receives a message from the backend. The returned message is only valid until the next call to Receive.
func (f *Frontend) Receive() (BackendMessage, error) {
if !f.partialMsg {
header, err := f.cr.Next(5)
if err != nil {
return nil, translateEOFtoErrUnexpectedEOF(err)
}
f.msgType = header[0]
f.bodyLen = int(binary.BigEndian.Uint32(header[1:])) - 4
f.partialMsg = true
if f.bodyLen < 0 {
return nil, errors.New("invalid message with negative body length received")
}
}
msgBody, err := f.cr.Next(f.bodyLen)
if err != nil {
return nil, translateEOFtoErrUnexpectedEOF(err)
}
f.partialMsg = false
var msg BackendMessage
switch f.msgType {
case '1':
msg = &f.parseComplete
case '2':
msg = &f.bindComplete
case '3':
msg = &f.closeComplete
case 'A':
msg = &f.notificationResponse
case 'c':
msg = &f.copyDone
case 'C':
msg = &f.commandComplete
case 'd':
msg = &f.copyData
case 'D':
msg = &f.dataRow
case 'E':
msg = &f.errorResponse
case 'G':
msg = &f.copyInResponse
case 'H':
msg = &f.copyOutResponse
case 'I':
msg = &f.emptyQueryResponse
case 'K':
msg = &f.backendKeyData
case 'n':
msg = &f.noData
case 'N':
msg = &f.noticeResponse
case 'R':
var err error
msg, err = f.findAuthenticationMessageType(msgBody)
if err != nil {
return nil, err
}
case 's':
msg = &f.portalSuspended
case 'S':
msg = &f.parameterStatus
case 't':
msg = &f.parameterDescription
case 'T':
msg = &f.rowDescription
case 'V':
msg = &f.functionCallResponse
case 'W':
msg = &f.copyBothResponse
case 'Z':
msg = &f.readyForQuery
default:
return nil, fmt.Errorf("unknown message type: %c", f.msgType)
}
err = msg.Decode(msgBody)
return msg, err
}
// Authentication message type constants.
// See src/include/libpq/pqcomm.h for all
// constants.
const (
AuthTypeOk = 0
AuthTypeCleartextPassword = 3
AuthTypeMD5Password = 5
AuthTypeSCMCreds = 6
AuthTypeGSS = 7
AuthTypeGSSCont = 8
AuthTypeSSPI = 9
AuthTypeSASL = 10
AuthTypeSASLContinue = 11
AuthTypeSASLFinal = 12
)
func (f *Frontend) findAuthenticationMessageType(src []byte) (BackendMessage, error) {
if len(src) < 4 {
return nil, errors.New("authentication message too short")
}
f.authType = binary.BigEndian.Uint32(src[:4])
switch f.authType {
case AuthTypeOk:
return &f.authenticationOk, nil
case AuthTypeCleartextPassword:
return &f.authenticationCleartextPassword, nil
case AuthTypeMD5Password:
return &f.authenticationMD5Password, nil
case AuthTypeSCMCreds:
return nil, errors.New("AuthTypeSCMCreds is unimplemented")
case AuthTypeGSS:
return &f.authenticationGSS, nil
case AuthTypeGSSCont:
return &f.authenticationGSSContinue, nil
case AuthTypeSSPI:
return nil, errors.New("AuthTypeSSPI is unimplemented")
case AuthTypeSASL:
return &f.authenticationSASL, nil
case AuthTypeSASLContinue:
return &f.authenticationSASLContinue, nil
case AuthTypeSASLFinal:
return &f.authenticationSASLFinal, nil
default:
return nil, fmt.Errorf("unknown authentication type: %d", f.authType)
}
}
// GetAuthType returns the authType used in the current state of the frontend.
// See SetAuthType for more information.
func (f *Frontend) GetAuthType() uint32 {
return f.authType
}
-149
View File
@@ -1,149 +0,0 @@
# 1.12.0 (August 6, 2022)
* Add JSONArray (Jakob Ackermann)
* Support Inet from fmt.Stringer and encoding.TextMarshaler (Ville Skyttä)
* Support UUID from fmt.Stringer interface (Lasse Hyldahl Jensen)
* Fix: shopspring-numeric extension does not panic on NaN
* Numeric can be assigned to string
* Fix: Do not send IPv4 networks as IPv4-mapped IPv6 (William Storey)
* Fix: PlanScan for interface{}(nil) (James Hartig)
* Fix: *sql.Scanner for NULL handling (James Hartig)
* Timestamp[tz].Set() supports string (Harmen)
* Fix: Hstore AssignTo with map of *string (Diego Becciolini)
# 1.11.0 (April 21, 2022)
* Add multirange for numeric, int4, and int8 (Vu)
* JSONBArray now supports json.RawMessage (Jens Emil Schulz Østergaard)
* Add RecordArray (WGH)
* Add UnmarshalJSON to pgtype.Int2
* Hstore.Set accepts map[string]Text
# 1.10.0 (February 7, 2022)
* Normalize UTC timestamps to comply with stdlib (Torkel Rogstad)
* Assign Numeric to *big.Rat (Oleg Lomaka)
* Fix typo in float8 error message (Pinank Solanki)
* Scan type aliases for floating point types (Collin Forsyth)
# 1.9.1 (November 28, 2021)
* Fix: binary timestamp is assumed to be in UTC (restored behavior changed in v1.9.0)
# 1.9.0 (November 20, 2021)
* Fix binary hstore null decoding
* Add shopspring/decimal.NullDecimal support to integration (Eli Treuherz)
* Inet.Set supports bare IP address (Carl Dunham)
* Add zeronull.Float8
* Fix NULL being lost when scanning unknown OID into sql.Scanner
* Fix BPChar.AssignTo **rune
* Add support for fmt.Stringer and driver.Valuer in String fields encoding (Jan Dubsky)
* Fix really big timestamp(tz)s binary format parsing (e.g. year 294276) (Jim Tsao)
* Support `map[string]*string` as hstore (Adrian Sieger)
* Fix parsing text array with negative bounds
* Add infinity support for numeric (Jim Tsao)
# 1.8.1 (July 24, 2021)
* Cleaned up Go module dependency chain
# 1.8.0 (July 10, 2021)
* Maintain host bits for inet types (Cameron Daniel)
* Support pointers of wrapping structs (Ivan Daunis)
* Register JSONBArray at NewConnInfo() (Rueian)
* CompositeTextScanner handles backslash escapes
# 1.7.0 (March 25, 2021)
* Fix scanning int into **sql.Scanner implementor
* Add tsrange array type (Vasilii Novikov)
* Fix: escaped strings when they start or end with a newline char (Stephane Martin)
* Accept nil *time.Time in Time.Set
* Fix numeric NaN support
* Use Go 1.13 errors instead of xerrors
# 1.6.2 (December 3, 2020)
* Fix panic on assigning empty array to non-slice or array
* Fix text array parsing disambiguates NULL and "NULL"
* Fix Timestamptz.DecodeText with too short text
# 1.6.1 (October 31, 2020)
* Fix simple protocol empty array support
# 1.6.0 (October 24, 2020)
* Fix AssignTo pointer to pointer to slice and named types.
* Fix zero length array assignment (Simo Haasanen)
* Add float64, float32 convert to int2, int4, int8 (lqu3j)
* Support setting infinite timestamps (Erik Agsjö)
* Polygon improvements (duohedron)
* Fix Inet.Set with nil (Tomas Volf)
# 1.5.0 (September 26, 2020)
* Add slice of slice mapping to multi-dimensional arrays (Simo Haasanen)
* Fix JSONBArray
* Fix selecting empty array
* Text formatted values except bytea can be directly scanned to []byte
* Add JSON marshalling for UUID (bakmataliev)
* Improve point type conversions (bakmataliev)
# 1.4.2 (July 22, 2020)
* Fix encoding of a large composite data type (Yaz Saito)
# 1.4.1 (July 14, 2020)
* Fix ArrayType DecodeBinary empty array breaks future reads
# 1.4.0 (June 27, 2020)
* Add JSON support to ext/gofrs-uuid
* Performance improvements in Scan path
* Improved ext/shopspring-numeric binary decoding performance
* Add composite type support (Maxim Ivanov and Jack Christensen)
* Add better generic enum type support
* Add generic array type support
* Clarify and normalize Value semantics
* Fix hstore with empty string values
* Numeric supports NaN values (leighhopcroft)
* Add slice of pointer support to array types (megaturbo)
* Add jsonb array type (tserakhau)
* Allow converting intervals with months and days to duration
# 1.3.0 (March 30, 2020)
* Get implemented on T instead of *T
* Set will call Get on src if possible
* Range types Set method supports its own type, string, and nil
* Date.Set parses string
* Fix correct format verb for unknown type error (Robert Welin)
* Truncate nanoseconds in EncodeText for Timestamptz and Timestamp
# 1.2.0 (February 5, 2020)
* Add zeronull package for easier NULL <-> zero conversion
* Add JSON marshalling for shopspring-numeric extension
* Add JSON marshalling for Bool, Date, JSON/B, Timestamptz (Jeffrey Stiles)
* Fix null status in UnmarshalJSON for some types (Jeffrey Stiles)
# 1.1.0 (January 11, 2020)
* Add PostgreSQL time type support
* Add more automatic conversions of integer arrays of different types (Jean-Philippe Quéméner)
# 1.0.3 (November 16, 2019)
* Support initializing Array types from a slice of the value (Alex Gaynor)
# 1.0.2 (October 22, 2019)
* Fix scan into null into pointer to pointer implementing Decode* interface. (Jeremy Altavilla)
# 1.0.1 (September 19, 2019)
* Fix daterange OID
-8
View File
@@ -1,8 +0,0 @@
[![](https://godoc.org/github.com/jackc/pgtype?status.svg)](https://godoc.org/github.com/jackc/pgtype)
![CI](https://github.com/jackc/pgtype/workflows/CI/badge.svg)
# pgtype
pgtype implements Go types for over 70 PostgreSQL types. pgtype is the type system underlying the
https://github.com/jackc/pgx PostgreSQL driver. These types support the binary format for enhanced performance with pgx.
They also support the database/sql `Scan` and `Value` interfaces and can be used with https://github.com/lib/pq.
-138
View File
@@ -1,138 +0,0 @@
package pgtype
import (
"database/sql/driver"
"fmt"
)
// ACLItem is used for PostgreSQL's aclitem data type. A sample aclitem
// might look like this:
//
// postgres=arwdDxt/postgres
//
// Note, however, that because the user/role name part of an aclitem is
// an identifier, it follows all the usual formatting rules for SQL
// identifiers: if it contains spaces and other special characters,
// it should appear in double-quotes:
//
// postgres=arwdDxt/"role with spaces"
//
type ACLItem struct {
String string
Status Status
}
func (dst *ACLItem) Set(src interface{}) error {
if src == nil {
*dst = ACLItem{Status: Null}
return nil
}
if value, ok := src.(interface{ Get() interface{} }); ok {
value2 := value.Get()
if value2 != value {
return dst.Set(value2)
}
}
switch value := src.(type) {
case string:
*dst = ACLItem{String: value, Status: Present}
case *string:
if value == nil {
*dst = ACLItem{Status: Null}
} else {
*dst = ACLItem{String: *value, Status: Present}
}
default:
if originalSrc, ok := underlyingStringType(src); ok {
return dst.Set(originalSrc)
}
return fmt.Errorf("cannot convert %v to ACLItem", value)
}
return nil
}
func (dst ACLItem) Get() interface{} {
switch dst.Status {
case Present:
return dst.String
case Null:
return nil
default:
return dst.Status
}
}
func (src *ACLItem) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
switch v := dst.(type) {
case *string:
*v = src.String
return nil
default:
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
return fmt.Errorf("unable to assign to %T", dst)
}
case Null:
return NullAssignTo(dst)
}
return fmt.Errorf("cannot decode %#v into %T", src, dst)
}
func (dst *ACLItem) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = ACLItem{Status: Null}
return nil
}
*dst = ACLItem{String: string(src), Status: Present}
return nil
}
func (src ACLItem) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
return append(buf, src.String...), nil
}
// Scan implements the database/sql Scanner interface.
func (dst *ACLItem) Scan(src interface{}) error {
if src == nil {
*dst = ACLItem{Status: Null}
return nil
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src ACLItem) Value() (driver.Value, error) {
switch src.Status {
case Present:
return src.String, nil
case Null:
return nil, nil
default:
return nil, errUndefined
}
}
-428
View File
@@ -1,428 +0,0 @@
// Code generated by erb. DO NOT EDIT.
package pgtype
import (
"database/sql/driver"
"fmt"
"reflect"
)
type ACLItemArray struct {
Elements []ACLItem
Dimensions []ArrayDimension
Status Status
}
func (dst *ACLItemArray) Set(src interface{}) error {
// untyped nil and typed nil interfaces are different
if src == nil {
*dst = ACLItemArray{Status: Null}
return nil
}
if value, ok := src.(interface{ Get() interface{} }); ok {
value2 := value.Get()
if value2 != value {
return dst.Set(value2)
}
}
// Attempt to match to select common types:
switch value := src.(type) {
case []string:
if value == nil {
*dst = ACLItemArray{Status: Null}
} else if len(value) == 0 {
*dst = ACLItemArray{Status: Present}
} else {
elements := make([]ACLItem, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = ACLItemArray{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []*string:
if value == nil {
*dst = ACLItemArray{Status: Null}
} else if len(value) == 0 {
*dst = ACLItemArray{Status: Present}
} else {
elements := make([]ACLItem, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = ACLItemArray{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []ACLItem:
if value == nil {
*dst = ACLItemArray{Status: Null}
} else if len(value) == 0 {
*dst = ACLItemArray{Status: Present}
} else {
*dst = ACLItemArray{
Elements: value,
Dimensions: []ArrayDimension{{Length: int32(len(value)), LowerBound: 1}},
Status: Present,
}
}
default:
// Fallback to reflection if an optimised match was not found.
// The reflection is necessary for arrays and multidimensional slices,
// but it comes with a 20-50% performance penalty for large arrays/slices
reflectedValue := reflect.ValueOf(src)
if !reflectedValue.IsValid() || reflectedValue.IsZero() {
*dst = ACLItemArray{Status: Null}
return nil
}
dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
if !ok {
return fmt.Errorf("cannot find dimensions of %v for ACLItemArray", src)
}
if elementsLength == 0 {
*dst = ACLItemArray{Status: Present}
return nil
}
if len(dimensions) == 0 {
if originalSrc, ok := underlyingSliceType(src); ok {
return dst.Set(originalSrc)
}
return fmt.Errorf("cannot convert %v to ACLItemArray", src)
}
*dst = ACLItemArray{
Elements: make([]ACLItem, elementsLength),
Dimensions: dimensions,
Status: Present,
}
elementCount, err := dst.setRecursive(reflectedValue, 0, 0)
if err != nil {
// Maybe the target was one dimension too far, try again:
if len(dst.Dimensions) > 1 {
dst.Dimensions = dst.Dimensions[:len(dst.Dimensions)-1]
elementsLength = 0
for _, dim := range dst.Dimensions {
if elementsLength == 0 {
elementsLength = int(dim.Length)
} else {
elementsLength *= int(dim.Length)
}
}
dst.Elements = make([]ACLItem, elementsLength)
elementCount, err = dst.setRecursive(reflectedValue, 0, 0)
if err != nil {
return err
}
} else {
return err
}
}
if elementCount != len(dst.Elements) {
return fmt.Errorf("cannot convert %v to ACLItemArray, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
}
}
return nil
}
func (dst *ACLItemArray) setRecursive(value reflect.Value, index, dimension int) (int, error) {
switch value.Kind() {
case reflect.Array:
fallthrough
case reflect.Slice:
if len(dst.Dimensions) == dimension {
break
}
valueLen := value.Len()
if int32(valueLen) != dst.Dimensions[dimension].Length {
return 0, fmt.Errorf("multidimensional arrays must have array expressions with matching dimensions")
}
for i := 0; i < valueLen; i++ {
var err error
index, err = dst.setRecursive(value.Index(i), index, dimension+1)
if err != nil {
return 0, err
}
}
return index, nil
}
if !value.CanInterface() {
return 0, fmt.Errorf("cannot convert all values to ACLItemArray")
}
if err := dst.Elements[index].Set(value.Interface()); err != nil {
return 0, fmt.Errorf("%v in ACLItemArray", err)
}
index++
return index, nil
}
func (dst ACLItemArray) Get() interface{} {
switch dst.Status {
case Present:
return dst
case Null:
return nil
default:
return dst.Status
}
}
func (src *ACLItemArray) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
if len(src.Dimensions) <= 1 {
// Attempt to match to select common types:
switch v := dst.(type) {
case *[]string:
*v = make([]string, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]*string:
*v = make([]*string, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
}
}
// Try to convert to something AssignTo can use directly.
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
// Fallback to reflection if an optimised match was not found.
// The reflection is necessary for arrays and multidimensional slices,
// but it comes with a 20-50% performance penalty for large arrays/slices
value := reflect.ValueOf(dst)
if value.Kind() == reflect.Ptr {
value = value.Elem()
}
switch value.Kind() {
case reflect.Array, reflect.Slice:
default:
return fmt.Errorf("cannot assign %T to %T", src, dst)
}
if len(src.Elements) == 0 {
if value.Kind() == reflect.Slice {
value.Set(reflect.MakeSlice(value.Type(), 0, 0))
return nil
}
}
elementCount, err := src.assignToRecursive(value, 0, 0)
if err != nil {
return err
}
if elementCount != len(src.Elements) {
return fmt.Errorf("cannot assign %v, needed to assign %d elements, but only assigned %d", dst, len(src.Elements), elementCount)
}
return nil
case Null:
return NullAssignTo(dst)
}
return fmt.Errorf("cannot decode %#v into %T", src, dst)
}
func (src *ACLItemArray) assignToRecursive(value reflect.Value, index, dimension int) (int, error) {
switch kind := value.Kind(); kind {
case reflect.Array:
fallthrough
case reflect.Slice:
if len(src.Dimensions) == dimension {
break
}
length := int(src.Dimensions[dimension].Length)
if reflect.Array == kind {
typ := value.Type()
if typ.Len() != length {
return 0, fmt.Errorf("expected size %d array, but %s has size %d array", length, typ, typ.Len())
}
value.Set(reflect.New(typ).Elem())
} else {
value.Set(reflect.MakeSlice(value.Type(), length, length))
}
var err error
for i := 0; i < length; i++ {
index, err = src.assignToRecursive(value.Index(i), index, dimension+1)
if err != nil {
return 0, err
}
}
return index, nil
}
if len(src.Dimensions) != dimension {
return 0, fmt.Errorf("incorrect dimensions, expected %d, found %d", len(src.Dimensions), dimension)
}
if !value.CanAddr() {
return 0, fmt.Errorf("cannot assign all values from ACLItemArray")
}
addr := value.Addr()
if !addr.CanInterface() {
return 0, fmt.Errorf("cannot assign all values from ACLItemArray")
}
if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
return 0, err
}
index++
return index, nil
}
func (dst *ACLItemArray) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = ACLItemArray{Status: Null}
return nil
}
uta, err := ParseUntypedTextArray(string(src))
if err != nil {
return err
}
var elements []ACLItem
if len(uta.Elements) > 0 {
elements = make([]ACLItem, len(uta.Elements))
for i, s := range uta.Elements {
var elem ACLItem
var elemSrc []byte
if s != "NULL" || uta.Quoted[i] {
elemSrc = []byte(s)
}
err = elem.DecodeText(ci, elemSrc)
if err != nil {
return err
}
elements[i] = elem
}
}
*dst = ACLItemArray{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
return nil
}
func (src ACLItemArray) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
if len(src.Dimensions) == 0 {
return append(buf, '{', '}'), nil
}
buf = EncodeTextArrayDimensions(buf, src.Dimensions)
// dimElemCounts is the multiples of elements that each array lies on. For
// example, a single dimension array of length 4 would have a dimElemCounts of
// [4]. A multi-dimensional array of lengths [3,5,2] would have a
// dimElemCounts of [30,10,2]. This is used to simplify when to render a '{'
// or '}'.
dimElemCounts := make([]int, len(src.Dimensions))
dimElemCounts[len(src.Dimensions)-1] = int(src.Dimensions[len(src.Dimensions)-1].Length)
for i := len(src.Dimensions) - 2; i > -1; i-- {
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
}
inElemBuf := make([]byte, 0, 32)
for i, elem := range src.Elements {
if i > 0 {
buf = append(buf, ',')
}
for _, dec := range dimElemCounts {
if i%dec == 0 {
buf = append(buf, '{')
}
}
elemBuf, err := elem.EncodeText(ci, inElemBuf)
if err != nil {
return nil, err
}
if elemBuf == nil {
buf = append(buf, `NULL`...)
} else {
buf = append(buf, QuoteArrayElementIfNeeded(string(elemBuf))...)
}
for _, dec := range dimElemCounts {
if (i+1)%dec == 0 {
buf = append(buf, '}')
}
}
}
return buf, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *ACLItemArray) Scan(src interface{}) error {
if src == nil {
return dst.DecodeText(nil, nil)
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src ACLItemArray) Value() (driver.Value, error) {
buf, err := src.EncodeText(nil, nil)
if err != nil {
return nil, err
}
if buf == nil {
return nil, nil
}
return string(buf), nil
}
-353
View File
@@ -1,353 +0,0 @@
package pgtype
import (
"database/sql/driver"
"encoding/binary"
"fmt"
"reflect"
"github.com/jackc/pgio"
)
// ArrayType represents an array type. While it implements Value, this is only in service of its type conversion duties
// when registered as a data type in a ConnType. It should not be used directly as a Value. ArrayType is a convenience
// type for types that do not have a concrete array type.
type ArrayType struct {
elements []ValueTranscoder
dimensions []ArrayDimension
typeName string
newElement func() ValueTranscoder
elementOID uint32
status Status
}
func NewArrayType(typeName string, elementOID uint32, newElement func() ValueTranscoder) *ArrayType {
return &ArrayType{typeName: typeName, elementOID: elementOID, newElement: newElement}
}
func (at *ArrayType) NewTypeValue() Value {
return &ArrayType{
elements: at.elements,
dimensions: at.dimensions,
status: at.status,
typeName: at.typeName,
elementOID: at.elementOID,
newElement: at.newElement,
}
}
func (at *ArrayType) TypeName() string {
return at.typeName
}
func (dst *ArrayType) setNil() {
dst.elements = nil
dst.dimensions = nil
dst.status = Null
}
func (dst *ArrayType) Set(src interface{}) error {
// untyped nil and typed nil interfaces are different
if src == nil {
dst.setNil()
return nil
}
sliceVal := reflect.ValueOf(src)
if sliceVal.Kind() != reflect.Slice {
return fmt.Errorf("cannot set non-slice")
}
if sliceVal.IsNil() {
dst.setNil()
return nil
}
dst.elements = make([]ValueTranscoder, sliceVal.Len())
for i := range dst.elements {
v := dst.newElement()
err := v.Set(sliceVal.Index(i).Interface())
if err != nil {
return err
}
dst.elements[i] = v
}
dst.dimensions = []ArrayDimension{{Length: int32(len(dst.elements)), LowerBound: 1}}
dst.status = Present
return nil
}
func (dst ArrayType) Get() interface{} {
switch dst.status {
case Present:
elementValues := make([]interface{}, len(dst.elements))
for i := range dst.elements {
elementValues[i] = dst.elements[i].Get()
}
return elementValues
case Null:
return nil
default:
return dst.status
}
}
func (src *ArrayType) AssignTo(dst interface{}) error {
ptrSlice := reflect.ValueOf(dst)
if ptrSlice.Kind() != reflect.Ptr {
return fmt.Errorf("cannot assign to non-pointer")
}
sliceVal := ptrSlice.Elem()
sliceType := sliceVal.Type()
if sliceType.Kind() != reflect.Slice {
return fmt.Errorf("cannot assign to pointer to non-slice")
}
switch src.status {
case Present:
slice := reflect.MakeSlice(sliceType, len(src.elements), len(src.elements))
elemType := sliceType.Elem()
for i := range src.elements {
ptrElem := reflect.New(elemType)
err := src.elements[i].AssignTo(ptrElem.Interface())
if err != nil {
return err
}
slice.Index(i).Set(ptrElem.Elem())
}
sliceVal.Set(slice)
return nil
case Null:
sliceVal.Set(reflect.Zero(sliceType))
return nil
}
return fmt.Errorf("cannot decode %#v into %T", src, dst)
}
func (dst *ArrayType) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
dst.setNil()
return nil
}
uta, err := ParseUntypedTextArray(string(src))
if err != nil {
return err
}
var elements []ValueTranscoder
if len(uta.Elements) > 0 {
elements = make([]ValueTranscoder, len(uta.Elements))
for i, s := range uta.Elements {
elem := dst.newElement()
var elemSrc []byte
if s != "NULL" {
elemSrc = []byte(s)
}
err = elem.DecodeText(ci, elemSrc)
if err != nil {
return err
}
elements[i] = elem
}
}
dst.elements = elements
dst.dimensions = uta.Dimensions
dst.status = Present
return nil
}
func (dst *ArrayType) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
dst.setNil()
return nil
}
var arrayHeader ArrayHeader
rp, err := arrayHeader.DecodeBinary(ci, src)
if err != nil {
return err
}
var elements []ValueTranscoder
if len(arrayHeader.Dimensions) == 0 {
dst.elements = elements
dst.dimensions = arrayHeader.Dimensions
dst.status = Present
return nil
}
elementCount := arrayHeader.Dimensions[0].Length
for _, d := range arrayHeader.Dimensions[1:] {
elementCount *= d.Length
}
elements = make([]ValueTranscoder, elementCount)
for i := range elements {
elem := dst.newElement()
elemLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
rp += 4
var elemSrc []byte
if elemLen >= 0 {
elemSrc = src[rp : rp+elemLen]
rp += elemLen
}
err = elem.DecodeBinary(ci, elemSrc)
if err != nil {
return err
}
elements[i] = elem
}
dst.elements = elements
dst.dimensions = arrayHeader.Dimensions
dst.status = Present
return nil
}
func (src ArrayType) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
if len(src.dimensions) == 0 {
return append(buf, '{', '}'), nil
}
buf = EncodeTextArrayDimensions(buf, src.dimensions)
// dimElemCounts is the multiples of elements that each array lies on. For
// example, a single dimension array of length 4 would have a dimElemCounts of
// [4]. A multi-dimensional array of lengths [3,5,2] would have a
// dimElemCounts of [30,10,2]. This is used to simplify when to render a '{'
// or '}'.
dimElemCounts := make([]int, len(src.dimensions))
dimElemCounts[len(src.dimensions)-1] = int(src.dimensions[len(src.dimensions)-1].Length)
for i := len(src.dimensions) - 2; i > -1; i-- {
dimElemCounts[i] = int(src.dimensions[i].Length) * dimElemCounts[i+1]
}
inElemBuf := make([]byte, 0, 32)
for i, elem := range src.elements {
if i > 0 {
buf = append(buf, ',')
}
for _, dec := range dimElemCounts {
if i%dec == 0 {
buf = append(buf, '{')
}
}
elemBuf, err := elem.EncodeText(ci, inElemBuf)
if err != nil {
return nil, err
}
if elemBuf == nil {
buf = append(buf, `NULL`...)
} else {
buf = append(buf, QuoteArrayElementIfNeeded(string(elemBuf))...)
}
for _, dec := range dimElemCounts {
if (i+1)%dec == 0 {
buf = append(buf, '}')
}
}
}
return buf, nil
}
func (src ArrayType) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
arrayHeader := ArrayHeader{
Dimensions: src.dimensions,
ElementOID: int32(src.elementOID),
}
for i := range src.elements {
if src.elements[i].Get() == nil {
arrayHeader.ContainsNull = true
break
}
}
buf = arrayHeader.EncodeBinary(ci, buf)
for i := range src.elements {
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
elemBuf, err := src.elements[i].EncodeBinary(ci, buf)
if err != nil {
return nil, err
}
if elemBuf != nil {
buf = elemBuf
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
}
return buf, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *ArrayType) Scan(src interface{}) error {
if src == nil {
return dst.DecodeText(nil, nil)
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src ArrayType) Value() (driver.Value, error) {
buf, err := src.EncodeText(nil, nil)
if err != nil {
return nil, err
}
if buf == nil {
return nil, nil
}
return string(buf), nil
}
-45
View File
@@ -1,45 +0,0 @@
package pgtype
import (
"database/sql/driver"
)
type Bit Varbit
func (dst *Bit) Set(src interface{}) error {
return (*Varbit)(dst).Set(src)
}
func (dst Bit) Get() interface{} {
return (Varbit)(dst).Get()
}
func (src *Bit) AssignTo(dst interface{}) error {
return (*Varbit)(src).AssignTo(dst)
}
func (dst *Bit) DecodeBinary(ci *ConnInfo, src []byte) error {
return (*Varbit)(dst).DecodeBinary(ci, src)
}
func (src Bit) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
return (Varbit)(src).EncodeBinary(ci, buf)
}
func (dst *Bit) DecodeText(ci *ConnInfo, src []byte) error {
return (*Varbit)(dst).DecodeText(ci, src)
}
func (src Bit) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
return (Varbit)(src).EncodeText(ci, buf)
}
// Scan implements the database/sql Scanner interface.
func (dst *Bit) Scan(src interface{}) error {
return (*Varbit)(dst).Scan(src)
}
// Value implements the database/sql/driver Valuer interface.
func (src Bit) Value() (driver.Value, error) {
return (Varbit)(src).Value()
}
-217
View File
@@ -1,217 +0,0 @@
package pgtype
import (
"database/sql/driver"
"encoding/json"
"fmt"
"strconv"
)
type Bool struct {
Bool bool
Status Status
}
func (dst *Bool) Set(src interface{}) error {
if src == nil {
*dst = Bool{Status: Null}
return nil
}
if value, ok := src.(interface{ Get() interface{} }); ok {
value2 := value.Get()
if value2 != value {
return dst.Set(value2)
}
}
switch value := src.(type) {
case bool:
*dst = Bool{Bool: value, Status: Present}
case string:
bb, err := strconv.ParseBool(value)
if err != nil {
return err
}
*dst = Bool{Bool: bb, Status: Present}
case *bool:
if value == nil {
*dst = Bool{Status: Null}
} else {
return dst.Set(*value)
}
case *string:
if value == nil {
*dst = Bool{Status: Null}
} else {
return dst.Set(*value)
}
default:
if originalSrc, ok := underlyingBoolType(src); ok {
return dst.Set(originalSrc)
}
return fmt.Errorf("cannot convert %v to Bool", value)
}
return nil
}
func (dst Bool) Get() interface{} {
switch dst.Status {
case Present:
return dst.Bool
case Null:
return nil
default:
return dst.Status
}
}
func (src *Bool) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
switch v := dst.(type) {
case *bool:
*v = src.Bool
return nil
default:
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
return fmt.Errorf("unable to assign to %T", dst)
}
case Null:
return NullAssignTo(dst)
}
return fmt.Errorf("cannot decode %#v into %T", src, dst)
}
func (dst *Bool) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Bool{Status: Null}
return nil
}
if len(src) != 1 {
return fmt.Errorf("invalid length for bool: %v", len(src))
}
*dst = Bool{Bool: src[0] == 't', Status: Present}
return nil
}
func (dst *Bool) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Bool{Status: Null}
return nil
}
if len(src) != 1 {
return fmt.Errorf("invalid length for bool: %v", len(src))
}
*dst = Bool{Bool: src[0] == 1, Status: Present}
return nil
}
func (src Bool) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
if src.Bool {
buf = append(buf, 't')
} else {
buf = append(buf, 'f')
}
return buf, nil
}
func (src Bool) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
if src.Bool {
buf = append(buf, 1)
} else {
buf = append(buf, 0)
}
return buf, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *Bool) Scan(src interface{}) error {
if src == nil {
*dst = Bool{Status: Null}
return nil
}
switch src := src.(type) {
case bool:
*dst = Bool{Bool: src, Status: Present}
return nil
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src Bool) Value() (driver.Value, error) {
switch src.Status {
case Present:
return src.Bool, nil
case Null:
return nil, nil
default:
return nil, errUndefined
}
}
func (src Bool) MarshalJSON() ([]byte, error) {
switch src.Status {
case Present:
if src.Bool {
return []byte("true"), nil
} else {
return []byte("false"), nil
}
case Null:
return []byte("null"), nil
case Undefined:
return nil, errUndefined
}
return nil, errBadStatus
}
func (dst *Bool) UnmarshalJSON(b []byte) error {
var v *bool
err := json.Unmarshal(b, &v)
if err != nil {
return err
}
if v == nil {
*dst = Bool{Status: Null}
} else {
*dst = Bool{Bool: *v, Status: Present}
}
return nil
}
-517
View File
@@ -1,517 +0,0 @@
// Code generated by erb. DO NOT EDIT.
package pgtype
import (
"database/sql/driver"
"encoding/binary"
"fmt"
"reflect"
"github.com/jackc/pgio"
)
type BoolArray struct {
Elements []Bool
Dimensions []ArrayDimension
Status Status
}
func (dst *BoolArray) Set(src interface{}) error {
// untyped nil and typed nil interfaces are different
if src == nil {
*dst = BoolArray{Status: Null}
return nil
}
if value, ok := src.(interface{ Get() interface{} }); ok {
value2 := value.Get()
if value2 != value {
return dst.Set(value2)
}
}
// Attempt to match to select common types:
switch value := src.(type) {
case []bool:
if value == nil {
*dst = BoolArray{Status: Null}
} else if len(value) == 0 {
*dst = BoolArray{Status: Present}
} else {
elements := make([]Bool, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = BoolArray{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []*bool:
if value == nil {
*dst = BoolArray{Status: Null}
} else if len(value) == 0 {
*dst = BoolArray{Status: Present}
} else {
elements := make([]Bool, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = BoolArray{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []Bool:
if value == nil {
*dst = BoolArray{Status: Null}
} else if len(value) == 0 {
*dst = BoolArray{Status: Present}
} else {
*dst = BoolArray{
Elements: value,
Dimensions: []ArrayDimension{{Length: int32(len(value)), LowerBound: 1}},
Status: Present,
}
}
default:
// Fallback to reflection if an optimised match was not found.
// The reflection is necessary for arrays and multidimensional slices,
// but it comes with a 20-50% performance penalty for large arrays/slices
reflectedValue := reflect.ValueOf(src)
if !reflectedValue.IsValid() || reflectedValue.IsZero() {
*dst = BoolArray{Status: Null}
return nil
}
dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
if !ok {
return fmt.Errorf("cannot find dimensions of %v for BoolArray", src)
}
if elementsLength == 0 {
*dst = BoolArray{Status: Present}
return nil
}
if len(dimensions) == 0 {
if originalSrc, ok := underlyingSliceType(src); ok {
return dst.Set(originalSrc)
}
return fmt.Errorf("cannot convert %v to BoolArray", src)
}
*dst = BoolArray{
Elements: make([]Bool, elementsLength),
Dimensions: dimensions,
Status: Present,
}
elementCount, err := dst.setRecursive(reflectedValue, 0, 0)
if err != nil {
// Maybe the target was one dimension too far, try again:
if len(dst.Dimensions) > 1 {
dst.Dimensions = dst.Dimensions[:len(dst.Dimensions)-1]
elementsLength = 0
for _, dim := range dst.Dimensions {
if elementsLength == 0 {
elementsLength = int(dim.Length)
} else {
elementsLength *= int(dim.Length)
}
}
dst.Elements = make([]Bool, elementsLength)
elementCount, err = dst.setRecursive(reflectedValue, 0, 0)
if err != nil {
return err
}
} else {
return err
}
}
if elementCount != len(dst.Elements) {
return fmt.Errorf("cannot convert %v to BoolArray, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
}
}
return nil
}
func (dst *BoolArray) setRecursive(value reflect.Value, index, dimension int) (int, error) {
switch value.Kind() {
case reflect.Array:
fallthrough
case reflect.Slice:
if len(dst.Dimensions) == dimension {
break
}
valueLen := value.Len()
if int32(valueLen) != dst.Dimensions[dimension].Length {
return 0, fmt.Errorf("multidimensional arrays must have array expressions with matching dimensions")
}
for i := 0; i < valueLen; i++ {
var err error
index, err = dst.setRecursive(value.Index(i), index, dimension+1)
if err != nil {
return 0, err
}
}
return index, nil
}
if !value.CanInterface() {
return 0, fmt.Errorf("cannot convert all values to BoolArray")
}
if err := dst.Elements[index].Set(value.Interface()); err != nil {
return 0, fmt.Errorf("%v in BoolArray", err)
}
index++
return index, nil
}
func (dst BoolArray) Get() interface{} {
switch dst.Status {
case Present:
return dst
case Null:
return nil
default:
return dst.Status
}
}
func (src *BoolArray) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
if len(src.Dimensions) <= 1 {
// Attempt to match to select common types:
switch v := dst.(type) {
case *[]bool:
*v = make([]bool, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]*bool:
*v = make([]*bool, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
}
}
// Try to convert to something AssignTo can use directly.
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
// Fallback to reflection if an optimised match was not found.
// The reflection is necessary for arrays and multidimensional slices,
// but it comes with a 20-50% performance penalty for large arrays/slices
value := reflect.ValueOf(dst)
if value.Kind() == reflect.Ptr {
value = value.Elem()
}
switch value.Kind() {
case reflect.Array, reflect.Slice:
default:
return fmt.Errorf("cannot assign %T to %T", src, dst)
}
if len(src.Elements) == 0 {
if value.Kind() == reflect.Slice {
value.Set(reflect.MakeSlice(value.Type(), 0, 0))
return nil
}
}
elementCount, err := src.assignToRecursive(value, 0, 0)
if err != nil {
return err
}
if elementCount != len(src.Elements) {
return fmt.Errorf("cannot assign %v, needed to assign %d elements, but only assigned %d", dst, len(src.Elements), elementCount)
}
return nil
case Null:
return NullAssignTo(dst)
}
return fmt.Errorf("cannot decode %#v into %T", src, dst)
}
func (src *BoolArray) assignToRecursive(value reflect.Value, index, dimension int) (int, error) {
switch kind := value.Kind(); kind {
case reflect.Array:
fallthrough
case reflect.Slice:
if len(src.Dimensions) == dimension {
break
}
length := int(src.Dimensions[dimension].Length)
if reflect.Array == kind {
typ := value.Type()
if typ.Len() != length {
return 0, fmt.Errorf("expected size %d array, but %s has size %d array", length, typ, typ.Len())
}
value.Set(reflect.New(typ).Elem())
} else {
value.Set(reflect.MakeSlice(value.Type(), length, length))
}
var err error
for i := 0; i < length; i++ {
index, err = src.assignToRecursive(value.Index(i), index, dimension+1)
if err != nil {
return 0, err
}
}
return index, nil
}
if len(src.Dimensions) != dimension {
return 0, fmt.Errorf("incorrect dimensions, expected %d, found %d", len(src.Dimensions), dimension)
}
if !value.CanAddr() {
return 0, fmt.Errorf("cannot assign all values from BoolArray")
}
addr := value.Addr()
if !addr.CanInterface() {
return 0, fmt.Errorf("cannot assign all values from BoolArray")
}
if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
return 0, err
}
index++
return index, nil
}
func (dst *BoolArray) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = BoolArray{Status: Null}
return nil
}
uta, err := ParseUntypedTextArray(string(src))
if err != nil {
return err
}
var elements []Bool
if len(uta.Elements) > 0 {
elements = make([]Bool, len(uta.Elements))
for i, s := range uta.Elements {
var elem Bool
var elemSrc []byte
if s != "NULL" || uta.Quoted[i] {
elemSrc = []byte(s)
}
err = elem.DecodeText(ci, elemSrc)
if err != nil {
return err
}
elements[i] = elem
}
}
*dst = BoolArray{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
return nil
}
func (dst *BoolArray) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = BoolArray{Status: Null}
return nil
}
var arrayHeader ArrayHeader
rp, err := arrayHeader.DecodeBinary(ci, src)
if err != nil {
return err
}
if len(arrayHeader.Dimensions) == 0 {
*dst = BoolArray{Dimensions: arrayHeader.Dimensions, Status: Present}
return nil
}
elementCount := arrayHeader.Dimensions[0].Length
for _, d := range arrayHeader.Dimensions[1:] {
elementCount *= d.Length
}
elements := make([]Bool, elementCount)
for i := range elements {
elemLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
rp += 4
var elemSrc []byte
if elemLen >= 0 {
elemSrc = src[rp : rp+elemLen]
rp += elemLen
}
err = elements[i].DecodeBinary(ci, elemSrc)
if err != nil {
return err
}
}
*dst = BoolArray{Elements: elements, Dimensions: arrayHeader.Dimensions, Status: Present}
return nil
}
func (src BoolArray) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
if len(src.Dimensions) == 0 {
return append(buf, '{', '}'), nil
}
buf = EncodeTextArrayDimensions(buf, src.Dimensions)
// dimElemCounts is the multiples of elements that each array lies on. For
// example, a single dimension array of length 4 would have a dimElemCounts of
// [4]. A multi-dimensional array of lengths [3,5,2] would have a
// dimElemCounts of [30,10,2]. This is used to simplify when to render a '{'
// or '}'.
dimElemCounts := make([]int, len(src.Dimensions))
dimElemCounts[len(src.Dimensions)-1] = int(src.Dimensions[len(src.Dimensions)-1].Length)
for i := len(src.Dimensions) - 2; i > -1; i-- {
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
}
inElemBuf := make([]byte, 0, 32)
for i, elem := range src.Elements {
if i > 0 {
buf = append(buf, ',')
}
for _, dec := range dimElemCounts {
if i%dec == 0 {
buf = append(buf, '{')
}
}
elemBuf, err := elem.EncodeText(ci, inElemBuf)
if err != nil {
return nil, err
}
if elemBuf == nil {
buf = append(buf, `NULL`...)
} else {
buf = append(buf, QuoteArrayElementIfNeeded(string(elemBuf))...)
}
for _, dec := range dimElemCounts {
if (i+1)%dec == 0 {
buf = append(buf, '}')
}
}
}
return buf, nil
}
func (src BoolArray) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
arrayHeader := ArrayHeader{
Dimensions: src.Dimensions,
}
if dt, ok := ci.DataTypeForName("bool"); ok {
arrayHeader.ElementOID = int32(dt.OID)
} else {
return nil, fmt.Errorf("unable to find oid for type name %v", "bool")
}
for i := range src.Elements {
if src.Elements[i].Status == Null {
arrayHeader.ContainsNull = true
break
}
}
buf = arrayHeader.EncodeBinary(ci, buf)
for i := range src.Elements {
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
elemBuf, err := src.Elements[i].EncodeBinary(ci, buf)
if err != nil {
return nil, err
}
if elemBuf != nil {
buf = elemBuf
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
}
return buf, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *BoolArray) Scan(src interface{}) error {
if src == nil {
return dst.DecodeText(nil, nil)
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src BoolArray) Value() (driver.Value, error) {
buf, err := src.EncodeText(nil, nil)
if err != nil {
return nil, err
}
if buf == nil {
return nil, nil
}
return string(buf), nil
}
-165
View File
@@ -1,165 +0,0 @@
package pgtype
import (
"database/sql/driver"
"encoding/binary"
"fmt"
"math"
"strconv"
"strings"
"github.com/jackc/pgio"
)
type Box struct {
P [2]Vec2
Status Status
}
func (dst *Box) Set(src interface{}) error {
return fmt.Errorf("cannot convert %v to Box", src)
}
func (dst Box) Get() interface{} {
switch dst.Status {
case Present:
return dst
case Null:
return nil
default:
return dst.Status
}
}
func (src *Box) AssignTo(dst interface{}) error {
return fmt.Errorf("cannot assign %v to %T", src, dst)
}
func (dst *Box) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Box{Status: Null}
return nil
}
if len(src) < 11 {
return fmt.Errorf("invalid length for Box: %v", len(src))
}
str := string(src[1:])
var end int
end = strings.IndexByte(str, ',')
x1, err := strconv.ParseFloat(str[:end], 64)
if err != nil {
return err
}
str = str[end+1:]
end = strings.IndexByte(str, ')')
y1, err := strconv.ParseFloat(str[:end], 64)
if err != nil {
return err
}
str = str[end+3:]
end = strings.IndexByte(str, ',')
x2, err := strconv.ParseFloat(str[:end], 64)
if err != nil {
return err
}
str = str[end+1 : len(str)-1]
y2, err := strconv.ParseFloat(str, 64)
if err != nil {
return err
}
*dst = Box{P: [2]Vec2{{x1, y1}, {x2, y2}}, Status: Present}
return nil
}
func (dst *Box) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Box{Status: Null}
return nil
}
if len(src) != 32 {
return fmt.Errorf("invalid length for Box: %v", len(src))
}
x1 := binary.BigEndian.Uint64(src)
y1 := binary.BigEndian.Uint64(src[8:])
x2 := binary.BigEndian.Uint64(src[16:])
y2 := binary.BigEndian.Uint64(src[24:])
*dst = Box{
P: [2]Vec2{
{math.Float64frombits(x1), math.Float64frombits(y1)},
{math.Float64frombits(x2), math.Float64frombits(y2)},
},
Status: Present,
}
return nil
}
func (src Box) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
buf = append(buf, fmt.Sprintf(`(%s,%s),(%s,%s)`,
strconv.FormatFloat(src.P[0].X, 'f', -1, 64),
strconv.FormatFloat(src.P[0].Y, 'f', -1, 64),
strconv.FormatFloat(src.P[1].X, 'f', -1, 64),
strconv.FormatFloat(src.P[1].Y, 'f', -1, 64),
)...)
return buf, nil
}
func (src Box) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
buf = pgio.AppendUint64(buf, math.Float64bits(src.P[0].X))
buf = pgio.AppendUint64(buf, math.Float64bits(src.P[0].Y))
buf = pgio.AppendUint64(buf, math.Float64bits(src.P[1].X))
buf = pgio.AppendUint64(buf, math.Float64bits(src.P[1].Y))
return buf, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *Box) Scan(src interface{}) error {
if src == nil {
*dst = Box{Status: Null}
return nil
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src Box) Value() (driver.Value, error) {
return EncodeValueText(src)
}
-93
View File
@@ -1,93 +0,0 @@
package pgtype
import (
"database/sql/driver"
"fmt"
)
// BPChar is fixed-length, blank padded char type
// character(n), char(n)
type BPChar Text
// Set converts from src to dst.
func (dst *BPChar) Set(src interface{}) error {
return (*Text)(dst).Set(src)
}
// Get returns underlying value
func (dst BPChar) Get() interface{} {
return (Text)(dst).Get()
}
// AssignTo assigns from src to dst.
func (src *BPChar) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
switch v := dst.(type) {
case *rune:
runes := []rune(src.String)
if len(runes) == 1 {
*v = runes[0]
return nil
}
case *string:
*v = src.String
return nil
case *[]byte:
*v = make([]byte, len(src.String))
copy(*v, src.String)
return nil
default:
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
return fmt.Errorf("unable to assign to %T", dst)
}
case Null:
return NullAssignTo(dst)
}
return fmt.Errorf("cannot decode %#v into %T", src, dst)
}
func (BPChar) PreferredResultFormat() int16 {
return TextFormatCode
}
func (dst *BPChar) DecodeText(ci *ConnInfo, src []byte) error {
return (*Text)(dst).DecodeText(ci, src)
}
func (dst *BPChar) DecodeBinary(ci *ConnInfo, src []byte) error {
return (*Text)(dst).DecodeBinary(ci, src)
}
func (BPChar) PreferredParamFormat() int16 {
return TextFormatCode
}
func (src BPChar) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
return (Text)(src).EncodeText(ci, buf)
}
func (src BPChar) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
return (Text)(src).EncodeBinary(ci, buf)
}
// Scan implements the database/sql Scanner interface.
func (dst *BPChar) Scan(src interface{}) error {
return (*Text)(dst).Scan(src)
}
// Value implements the database/sql/driver Valuer interface.
func (src BPChar) Value() (driver.Value, error) {
return (Text)(src).Value()
}
func (src BPChar) MarshalJSON() ([]byte, error) {
return (Text)(src).MarshalJSON()
}
func (dst *BPChar) UnmarshalJSON(b []byte) error {
return (*Text)(dst).UnmarshalJSON(b)
}
-517
View File
@@ -1,517 +0,0 @@
// Code generated by erb. DO NOT EDIT.
package pgtype
import (
"database/sql/driver"
"encoding/binary"
"fmt"
"reflect"
"github.com/jackc/pgio"
)
type BPCharArray struct {
Elements []BPChar
Dimensions []ArrayDimension
Status Status
}
func (dst *BPCharArray) Set(src interface{}) error {
// untyped nil and typed nil interfaces are different
if src == nil {
*dst = BPCharArray{Status: Null}
return nil
}
if value, ok := src.(interface{ Get() interface{} }); ok {
value2 := value.Get()
if value2 != value {
return dst.Set(value2)
}
}
// Attempt to match to select common types:
switch value := src.(type) {
case []string:
if value == nil {
*dst = BPCharArray{Status: Null}
} else if len(value) == 0 {
*dst = BPCharArray{Status: Present}
} else {
elements := make([]BPChar, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = BPCharArray{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []*string:
if value == nil {
*dst = BPCharArray{Status: Null}
} else if len(value) == 0 {
*dst = BPCharArray{Status: Present}
} else {
elements := make([]BPChar, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = BPCharArray{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []BPChar:
if value == nil {
*dst = BPCharArray{Status: Null}
} else if len(value) == 0 {
*dst = BPCharArray{Status: Present}
} else {
*dst = BPCharArray{
Elements: value,
Dimensions: []ArrayDimension{{Length: int32(len(value)), LowerBound: 1}},
Status: Present,
}
}
default:
// Fallback to reflection if an optimised match was not found.
// The reflection is necessary for arrays and multidimensional slices,
// but it comes with a 20-50% performance penalty for large arrays/slices
reflectedValue := reflect.ValueOf(src)
if !reflectedValue.IsValid() || reflectedValue.IsZero() {
*dst = BPCharArray{Status: Null}
return nil
}
dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
if !ok {
return fmt.Errorf("cannot find dimensions of %v for BPCharArray", src)
}
if elementsLength == 0 {
*dst = BPCharArray{Status: Present}
return nil
}
if len(dimensions) == 0 {
if originalSrc, ok := underlyingSliceType(src); ok {
return dst.Set(originalSrc)
}
return fmt.Errorf("cannot convert %v to BPCharArray", src)
}
*dst = BPCharArray{
Elements: make([]BPChar, elementsLength),
Dimensions: dimensions,
Status: Present,
}
elementCount, err := dst.setRecursive(reflectedValue, 0, 0)
if err != nil {
// Maybe the target was one dimension too far, try again:
if len(dst.Dimensions) > 1 {
dst.Dimensions = dst.Dimensions[:len(dst.Dimensions)-1]
elementsLength = 0
for _, dim := range dst.Dimensions {
if elementsLength == 0 {
elementsLength = int(dim.Length)
} else {
elementsLength *= int(dim.Length)
}
}
dst.Elements = make([]BPChar, elementsLength)
elementCount, err = dst.setRecursive(reflectedValue, 0, 0)
if err != nil {
return err
}
} else {
return err
}
}
if elementCount != len(dst.Elements) {
return fmt.Errorf("cannot convert %v to BPCharArray, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
}
}
return nil
}
func (dst *BPCharArray) setRecursive(value reflect.Value, index, dimension int) (int, error) {
switch value.Kind() {
case reflect.Array:
fallthrough
case reflect.Slice:
if len(dst.Dimensions) == dimension {
break
}
valueLen := value.Len()
if int32(valueLen) != dst.Dimensions[dimension].Length {
return 0, fmt.Errorf("multidimensional arrays must have array expressions with matching dimensions")
}
for i := 0; i < valueLen; i++ {
var err error
index, err = dst.setRecursive(value.Index(i), index, dimension+1)
if err != nil {
return 0, err
}
}
return index, nil
}
if !value.CanInterface() {
return 0, fmt.Errorf("cannot convert all values to BPCharArray")
}
if err := dst.Elements[index].Set(value.Interface()); err != nil {
return 0, fmt.Errorf("%v in BPCharArray", err)
}
index++
return index, nil
}
func (dst BPCharArray) Get() interface{} {
switch dst.Status {
case Present:
return dst
case Null:
return nil
default:
return dst.Status
}
}
func (src *BPCharArray) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
if len(src.Dimensions) <= 1 {
// Attempt to match to select common types:
switch v := dst.(type) {
case *[]string:
*v = make([]string, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]*string:
*v = make([]*string, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
}
}
// Try to convert to something AssignTo can use directly.
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
// Fallback to reflection if an optimised match was not found.
// The reflection is necessary for arrays and multidimensional slices,
// but it comes with a 20-50% performance penalty for large arrays/slices
value := reflect.ValueOf(dst)
if value.Kind() == reflect.Ptr {
value = value.Elem()
}
switch value.Kind() {
case reflect.Array, reflect.Slice:
default:
return fmt.Errorf("cannot assign %T to %T", src, dst)
}
if len(src.Elements) == 0 {
if value.Kind() == reflect.Slice {
value.Set(reflect.MakeSlice(value.Type(), 0, 0))
return nil
}
}
elementCount, err := src.assignToRecursive(value, 0, 0)
if err != nil {
return err
}
if elementCount != len(src.Elements) {
return fmt.Errorf("cannot assign %v, needed to assign %d elements, but only assigned %d", dst, len(src.Elements), elementCount)
}
return nil
case Null:
return NullAssignTo(dst)
}
return fmt.Errorf("cannot decode %#v into %T", src, dst)
}
func (src *BPCharArray) assignToRecursive(value reflect.Value, index, dimension int) (int, error) {
switch kind := value.Kind(); kind {
case reflect.Array:
fallthrough
case reflect.Slice:
if len(src.Dimensions) == dimension {
break
}
length := int(src.Dimensions[dimension].Length)
if reflect.Array == kind {
typ := value.Type()
if typ.Len() != length {
return 0, fmt.Errorf("expected size %d array, but %s has size %d array", length, typ, typ.Len())
}
value.Set(reflect.New(typ).Elem())
} else {
value.Set(reflect.MakeSlice(value.Type(), length, length))
}
var err error
for i := 0; i < length; i++ {
index, err = src.assignToRecursive(value.Index(i), index, dimension+1)
if err != nil {
return 0, err
}
}
return index, nil
}
if len(src.Dimensions) != dimension {
return 0, fmt.Errorf("incorrect dimensions, expected %d, found %d", len(src.Dimensions), dimension)
}
if !value.CanAddr() {
return 0, fmt.Errorf("cannot assign all values from BPCharArray")
}
addr := value.Addr()
if !addr.CanInterface() {
return 0, fmt.Errorf("cannot assign all values from BPCharArray")
}
if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
return 0, err
}
index++
return index, nil
}
func (dst *BPCharArray) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = BPCharArray{Status: Null}
return nil
}
uta, err := ParseUntypedTextArray(string(src))
if err != nil {
return err
}
var elements []BPChar
if len(uta.Elements) > 0 {
elements = make([]BPChar, len(uta.Elements))
for i, s := range uta.Elements {
var elem BPChar
var elemSrc []byte
if s != "NULL" || uta.Quoted[i] {
elemSrc = []byte(s)
}
err = elem.DecodeText(ci, elemSrc)
if err != nil {
return err
}
elements[i] = elem
}
}
*dst = BPCharArray{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
return nil
}
func (dst *BPCharArray) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = BPCharArray{Status: Null}
return nil
}
var arrayHeader ArrayHeader
rp, err := arrayHeader.DecodeBinary(ci, src)
if err != nil {
return err
}
if len(arrayHeader.Dimensions) == 0 {
*dst = BPCharArray{Dimensions: arrayHeader.Dimensions, Status: Present}
return nil
}
elementCount := arrayHeader.Dimensions[0].Length
for _, d := range arrayHeader.Dimensions[1:] {
elementCount *= d.Length
}
elements := make([]BPChar, elementCount)
for i := range elements {
elemLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
rp += 4
var elemSrc []byte
if elemLen >= 0 {
elemSrc = src[rp : rp+elemLen]
rp += elemLen
}
err = elements[i].DecodeBinary(ci, elemSrc)
if err != nil {
return err
}
}
*dst = BPCharArray{Elements: elements, Dimensions: arrayHeader.Dimensions, Status: Present}
return nil
}
func (src BPCharArray) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
if len(src.Dimensions) == 0 {
return append(buf, '{', '}'), nil
}
buf = EncodeTextArrayDimensions(buf, src.Dimensions)
// dimElemCounts is the multiples of elements that each array lies on. For
// example, a single dimension array of length 4 would have a dimElemCounts of
// [4]. A multi-dimensional array of lengths [3,5,2] would have a
// dimElemCounts of [30,10,2]. This is used to simplify when to render a '{'
// or '}'.
dimElemCounts := make([]int, len(src.Dimensions))
dimElemCounts[len(src.Dimensions)-1] = int(src.Dimensions[len(src.Dimensions)-1].Length)
for i := len(src.Dimensions) - 2; i > -1; i-- {
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
}
inElemBuf := make([]byte, 0, 32)
for i, elem := range src.Elements {
if i > 0 {
buf = append(buf, ',')
}
for _, dec := range dimElemCounts {
if i%dec == 0 {
buf = append(buf, '{')
}
}
elemBuf, err := elem.EncodeText(ci, inElemBuf)
if err != nil {
return nil, err
}
if elemBuf == nil {
buf = append(buf, `NULL`...)
} else {
buf = append(buf, QuoteArrayElementIfNeeded(string(elemBuf))...)
}
for _, dec := range dimElemCounts {
if (i+1)%dec == 0 {
buf = append(buf, '}')
}
}
}
return buf, nil
}
func (src BPCharArray) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
arrayHeader := ArrayHeader{
Dimensions: src.Dimensions,
}
if dt, ok := ci.DataTypeForName("bpchar"); ok {
arrayHeader.ElementOID = int32(dt.OID)
} else {
return nil, fmt.Errorf("unable to find oid for type name %v", "bpchar")
}
for i := range src.Elements {
if src.Elements[i].Status == Null {
arrayHeader.ContainsNull = true
break
}
}
buf = arrayHeader.EncodeBinary(ci, buf)
for i := range src.Elements {
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
elemBuf, err := src.Elements[i].EncodeBinary(ci, buf)
if err != nil {
return nil, err
}
if elemBuf != nil {
buf = elemBuf
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
}
return buf, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *BPCharArray) Scan(src interface{}) error {
if src == nil {
return dst.DecodeText(nil, nil)
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src BPCharArray) Value() (driver.Value, error) {
buf, err := src.EncodeText(nil, nil)
if err != nil {
return nil, err
}
if buf == nil {
return nil, nil
}
return string(buf), nil
}
-163
View File
@@ -1,163 +0,0 @@
package pgtype
import (
"database/sql/driver"
"encoding/hex"
"fmt"
)
type Bytea struct {
Bytes []byte
Status Status
}
func (dst *Bytea) Set(src interface{}) error {
if src == nil {
*dst = Bytea{Status: Null}
return nil
}
if value, ok := src.(interface{ Get() interface{} }); ok {
value2 := value.Get()
if value2 != value {
return dst.Set(value2)
}
}
switch value := src.(type) {
case []byte:
if value != nil {
*dst = Bytea{Bytes: value, Status: Present}
} else {
*dst = Bytea{Status: Null}
}
default:
if originalSrc, ok := underlyingBytesType(src); ok {
return dst.Set(originalSrc)
}
return fmt.Errorf("cannot convert %v to Bytea", value)
}
return nil
}
func (dst Bytea) Get() interface{} {
switch dst.Status {
case Present:
return dst.Bytes
case Null:
return nil
default:
return dst.Status
}
}
func (src *Bytea) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
switch v := dst.(type) {
case *[]byte:
buf := make([]byte, len(src.Bytes))
copy(buf, src.Bytes)
*v = buf
return nil
default:
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
return fmt.Errorf("unable to assign to %T", dst)
}
case Null:
return NullAssignTo(dst)
}
return fmt.Errorf("cannot decode %#v into %T", src, dst)
}
// DecodeText only supports the hex format. This has been the default since
// PostgreSQL 9.0.
func (dst *Bytea) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Bytea{Status: Null}
return nil
}
if len(src) < 2 || src[0] != '\\' || src[1] != 'x' {
return fmt.Errorf("invalid hex format")
}
buf := make([]byte, (len(src)-2)/2)
_, err := hex.Decode(buf, src[2:])
if err != nil {
return err
}
*dst = Bytea{Bytes: buf, Status: Present}
return nil
}
func (dst *Bytea) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Bytea{Status: Null}
return nil
}
*dst = Bytea{Bytes: src, Status: Present}
return nil
}
func (src Bytea) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
buf = append(buf, `\x`...)
buf = append(buf, hex.EncodeToString(src.Bytes)...)
return buf, nil
}
func (src Bytea) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
return append(buf, src.Bytes...), nil
}
// Scan implements the database/sql Scanner interface.
func (dst *Bytea) Scan(src interface{}) error {
if src == nil {
*dst = Bytea{Status: Null}
return nil
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
buf := make([]byte, len(src))
copy(buf, src)
*dst = Bytea{Bytes: buf, Status: Present}
return nil
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src Bytea) Value() (driver.Value, error) {
switch src.Status {
case Present:
return src.Bytes, nil
case Null:
return nil, nil
default:
return nil, errUndefined
}
}
-489
View File
@@ -1,489 +0,0 @@
// Code generated by erb. DO NOT EDIT.
package pgtype
import (
"database/sql/driver"
"encoding/binary"
"fmt"
"reflect"
"github.com/jackc/pgio"
)
type ByteaArray struct {
Elements []Bytea
Dimensions []ArrayDimension
Status Status
}
func (dst *ByteaArray) Set(src interface{}) error {
// untyped nil and typed nil interfaces are different
if src == nil {
*dst = ByteaArray{Status: Null}
return nil
}
if value, ok := src.(interface{ Get() interface{} }); ok {
value2 := value.Get()
if value2 != value {
return dst.Set(value2)
}
}
// Attempt to match to select common types:
switch value := src.(type) {
case [][]byte:
if value == nil {
*dst = ByteaArray{Status: Null}
} else if len(value) == 0 {
*dst = ByteaArray{Status: Present}
} else {
elements := make([]Bytea, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = ByteaArray{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []Bytea:
if value == nil {
*dst = ByteaArray{Status: Null}
} else if len(value) == 0 {
*dst = ByteaArray{Status: Present}
} else {
*dst = ByteaArray{
Elements: value,
Dimensions: []ArrayDimension{{Length: int32(len(value)), LowerBound: 1}},
Status: Present,
}
}
default:
// Fallback to reflection if an optimised match was not found.
// The reflection is necessary for arrays and multidimensional slices,
// but it comes with a 20-50% performance penalty for large arrays/slices
reflectedValue := reflect.ValueOf(src)
if !reflectedValue.IsValid() || reflectedValue.IsZero() {
*dst = ByteaArray{Status: Null}
return nil
}
dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
if !ok {
return fmt.Errorf("cannot find dimensions of %v for ByteaArray", src)
}
if elementsLength == 0 {
*dst = ByteaArray{Status: Present}
return nil
}
if len(dimensions) == 0 {
if originalSrc, ok := underlyingSliceType(src); ok {
return dst.Set(originalSrc)
}
return fmt.Errorf("cannot convert %v to ByteaArray", src)
}
*dst = ByteaArray{
Elements: make([]Bytea, elementsLength),
Dimensions: dimensions,
Status: Present,
}
elementCount, err := dst.setRecursive(reflectedValue, 0, 0)
if err != nil {
// Maybe the target was one dimension too far, try again:
if len(dst.Dimensions) > 1 {
dst.Dimensions = dst.Dimensions[:len(dst.Dimensions)-1]
elementsLength = 0
for _, dim := range dst.Dimensions {
if elementsLength == 0 {
elementsLength = int(dim.Length)
} else {
elementsLength *= int(dim.Length)
}
}
dst.Elements = make([]Bytea, elementsLength)
elementCount, err = dst.setRecursive(reflectedValue, 0, 0)
if err != nil {
return err
}
} else {
return err
}
}
if elementCount != len(dst.Elements) {
return fmt.Errorf("cannot convert %v to ByteaArray, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
}
}
return nil
}
func (dst *ByteaArray) setRecursive(value reflect.Value, index, dimension int) (int, error) {
switch value.Kind() {
case reflect.Array:
fallthrough
case reflect.Slice:
if len(dst.Dimensions) == dimension {
break
}
valueLen := value.Len()
if int32(valueLen) != dst.Dimensions[dimension].Length {
return 0, fmt.Errorf("multidimensional arrays must have array expressions with matching dimensions")
}
for i := 0; i < valueLen; i++ {
var err error
index, err = dst.setRecursive(value.Index(i), index, dimension+1)
if err != nil {
return 0, err
}
}
return index, nil
}
if !value.CanInterface() {
return 0, fmt.Errorf("cannot convert all values to ByteaArray")
}
if err := dst.Elements[index].Set(value.Interface()); err != nil {
return 0, fmt.Errorf("%v in ByteaArray", err)
}
index++
return index, nil
}
func (dst ByteaArray) Get() interface{} {
switch dst.Status {
case Present:
return dst
case Null:
return nil
default:
return dst.Status
}
}
func (src *ByteaArray) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
if len(src.Dimensions) <= 1 {
// Attempt to match to select common types:
switch v := dst.(type) {
case *[][]byte:
*v = make([][]byte, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
}
}
// Try to convert to something AssignTo can use directly.
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
// Fallback to reflection if an optimised match was not found.
// The reflection is necessary for arrays and multidimensional slices,
// but it comes with a 20-50% performance penalty for large arrays/slices
value := reflect.ValueOf(dst)
if value.Kind() == reflect.Ptr {
value = value.Elem()
}
switch value.Kind() {
case reflect.Array, reflect.Slice:
default:
return fmt.Errorf("cannot assign %T to %T", src, dst)
}
if len(src.Elements) == 0 {
if value.Kind() == reflect.Slice {
value.Set(reflect.MakeSlice(value.Type(), 0, 0))
return nil
}
}
elementCount, err := src.assignToRecursive(value, 0, 0)
if err != nil {
return err
}
if elementCount != len(src.Elements) {
return fmt.Errorf("cannot assign %v, needed to assign %d elements, but only assigned %d", dst, len(src.Elements), elementCount)
}
return nil
case Null:
return NullAssignTo(dst)
}
return fmt.Errorf("cannot decode %#v into %T", src, dst)
}
func (src *ByteaArray) assignToRecursive(value reflect.Value, index, dimension int) (int, error) {
switch kind := value.Kind(); kind {
case reflect.Array:
fallthrough
case reflect.Slice:
if len(src.Dimensions) == dimension {
break
}
length := int(src.Dimensions[dimension].Length)
if reflect.Array == kind {
typ := value.Type()
if typ.Len() != length {
return 0, fmt.Errorf("expected size %d array, but %s has size %d array", length, typ, typ.Len())
}
value.Set(reflect.New(typ).Elem())
} else {
value.Set(reflect.MakeSlice(value.Type(), length, length))
}
var err error
for i := 0; i < length; i++ {
index, err = src.assignToRecursive(value.Index(i), index, dimension+1)
if err != nil {
return 0, err
}
}
return index, nil
}
if len(src.Dimensions) != dimension {
return 0, fmt.Errorf("incorrect dimensions, expected %d, found %d", len(src.Dimensions), dimension)
}
if !value.CanAddr() {
return 0, fmt.Errorf("cannot assign all values from ByteaArray")
}
addr := value.Addr()
if !addr.CanInterface() {
return 0, fmt.Errorf("cannot assign all values from ByteaArray")
}
if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
return 0, err
}
index++
return index, nil
}
func (dst *ByteaArray) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = ByteaArray{Status: Null}
return nil
}
uta, err := ParseUntypedTextArray(string(src))
if err != nil {
return err
}
var elements []Bytea
if len(uta.Elements) > 0 {
elements = make([]Bytea, len(uta.Elements))
for i, s := range uta.Elements {
var elem Bytea
var elemSrc []byte
if s != "NULL" || uta.Quoted[i] {
elemSrc = []byte(s)
}
err = elem.DecodeText(ci, elemSrc)
if err != nil {
return err
}
elements[i] = elem
}
}
*dst = ByteaArray{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
return nil
}
func (dst *ByteaArray) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = ByteaArray{Status: Null}
return nil
}
var arrayHeader ArrayHeader
rp, err := arrayHeader.DecodeBinary(ci, src)
if err != nil {
return err
}
if len(arrayHeader.Dimensions) == 0 {
*dst = ByteaArray{Dimensions: arrayHeader.Dimensions, Status: Present}
return nil
}
elementCount := arrayHeader.Dimensions[0].Length
for _, d := range arrayHeader.Dimensions[1:] {
elementCount *= d.Length
}
elements := make([]Bytea, elementCount)
for i := range elements {
elemLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
rp += 4
var elemSrc []byte
if elemLen >= 0 {
elemSrc = src[rp : rp+elemLen]
rp += elemLen
}
err = elements[i].DecodeBinary(ci, elemSrc)
if err != nil {
return err
}
}
*dst = ByteaArray{Elements: elements, Dimensions: arrayHeader.Dimensions, Status: Present}
return nil
}
func (src ByteaArray) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
if len(src.Dimensions) == 0 {
return append(buf, '{', '}'), nil
}
buf = EncodeTextArrayDimensions(buf, src.Dimensions)
// dimElemCounts is the multiples of elements that each array lies on. For
// example, a single dimension array of length 4 would have a dimElemCounts of
// [4]. A multi-dimensional array of lengths [3,5,2] would have a
// dimElemCounts of [30,10,2]. This is used to simplify when to render a '{'
// or '}'.
dimElemCounts := make([]int, len(src.Dimensions))
dimElemCounts[len(src.Dimensions)-1] = int(src.Dimensions[len(src.Dimensions)-1].Length)
for i := len(src.Dimensions) - 2; i > -1; i-- {
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
}
inElemBuf := make([]byte, 0, 32)
for i, elem := range src.Elements {
if i > 0 {
buf = append(buf, ',')
}
for _, dec := range dimElemCounts {
if i%dec == 0 {
buf = append(buf, '{')
}
}
elemBuf, err := elem.EncodeText(ci, inElemBuf)
if err != nil {
return nil, err
}
if elemBuf == nil {
buf = append(buf, `NULL`...)
} else {
buf = append(buf, QuoteArrayElementIfNeeded(string(elemBuf))...)
}
for _, dec := range dimElemCounts {
if (i+1)%dec == 0 {
buf = append(buf, '}')
}
}
}
return buf, nil
}
func (src ByteaArray) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
arrayHeader := ArrayHeader{
Dimensions: src.Dimensions,
}
if dt, ok := ci.DataTypeForName("bytea"); ok {
arrayHeader.ElementOID = int32(dt.OID)
} else {
return nil, fmt.Errorf("unable to find oid for type name %v", "bytea")
}
for i := range src.Elements {
if src.Elements[i].Status == Null {
arrayHeader.ContainsNull = true
break
}
}
buf = arrayHeader.EncodeBinary(ci, buf)
for i := range src.Elements {
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
elemBuf, err := src.Elements[i].EncodeBinary(ci, buf)
if err != nil {
return nil, err
}
if elemBuf != nil {
buf = elemBuf
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
}
return buf, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *ByteaArray) Scan(src interface{}) error {
if src == nil {
return dst.DecodeText(nil, nil)
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src ByteaArray) Value() (driver.Value, error) {
buf, err := src.EncodeText(nil, nil)
if err != nil {
return nil, err
}
if buf == nil {
return nil, nil
}
return string(buf), nil
}
-61
View File
@@ -1,61 +0,0 @@
package pgtype
import (
"database/sql/driver"
)
// CID is PostgreSQL's Command Identifier type.
//
// When one does
//
// select cmin, cmax, * from some_table;
//
// it is the data type of the cmin and cmax hidden system columns.
//
// It is currently implemented as an unsigned four byte integer.
// Its definition can be found in src/include/c.h as CommandId
// in the PostgreSQL sources.
type CID pguint32
// Set converts from src to dst. Note that as CID is not a general
// number type Set does not do automatic type conversion as other number
// types do.
func (dst *CID) Set(src interface{}) error {
return (*pguint32)(dst).Set(src)
}
func (dst CID) Get() interface{} {
return (pguint32)(dst).Get()
}
// AssignTo assigns from src to dst. Note that as CID is not a general number
// type AssignTo does not do automatic type conversion as other number types do.
func (src *CID) AssignTo(dst interface{}) error {
return (*pguint32)(src).AssignTo(dst)
}
func (dst *CID) DecodeText(ci *ConnInfo, src []byte) error {
return (*pguint32)(dst).DecodeText(ci, src)
}
func (dst *CID) DecodeBinary(ci *ConnInfo, src []byte) error {
return (*pguint32)(dst).DecodeBinary(ci, src)
}
func (src CID) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
return (pguint32)(src).EncodeText(ci, buf)
}
func (src CID) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
return (pguint32)(src).EncodeBinary(ci, buf)
}
// Scan implements the database/sql Scanner interface.
func (dst *CID) Scan(src interface{}) error {
return (*pguint32)(dst).Scan(src)
}
// Value implements the database/sql/driver Valuer interface.
func (src CID) Value() (driver.Value, error) {
return (pguint32)(src).Value()
}
-31
View File
@@ -1,31 +0,0 @@
package pgtype
type CIDR Inet
func (dst *CIDR) Set(src interface{}) error {
return (*Inet)(dst).Set(src)
}
func (dst CIDR) Get() interface{} {
return (Inet)(dst).Get()
}
func (src *CIDR) AssignTo(dst interface{}) error {
return (*Inet)(src).AssignTo(dst)
}
func (dst *CIDR) DecodeText(ci *ConnInfo, src []byte) error {
return (*Inet)(dst).DecodeText(ci, src)
}
func (dst *CIDR) DecodeBinary(ci *ConnInfo, src []byte) error {
return (*Inet)(dst).DecodeBinary(ci, src)
}
func (src CIDR) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
return (Inet)(src).EncodeText(ci, buf)
}
func (src CIDR) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
return (Inet)(src).EncodeBinary(ci, buf)
}
-546
View File
@@ -1,546 +0,0 @@
// Code generated by erb. DO NOT EDIT.
package pgtype
import (
"database/sql/driver"
"encoding/binary"
"fmt"
"net"
"reflect"
"github.com/jackc/pgio"
)
type CIDRArray struct {
Elements []CIDR
Dimensions []ArrayDimension
Status Status
}
func (dst *CIDRArray) Set(src interface{}) error {
// untyped nil and typed nil interfaces are different
if src == nil {
*dst = CIDRArray{Status: Null}
return nil
}
if value, ok := src.(interface{ Get() interface{} }); ok {
value2 := value.Get()
if value2 != value {
return dst.Set(value2)
}
}
// Attempt to match to select common types:
switch value := src.(type) {
case []*net.IPNet:
if value == nil {
*dst = CIDRArray{Status: Null}
} else if len(value) == 0 {
*dst = CIDRArray{Status: Present}
} else {
elements := make([]CIDR, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = CIDRArray{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []net.IP:
if value == nil {
*dst = CIDRArray{Status: Null}
} else if len(value) == 0 {
*dst = CIDRArray{Status: Present}
} else {
elements := make([]CIDR, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = CIDRArray{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []*net.IP:
if value == nil {
*dst = CIDRArray{Status: Null}
} else if len(value) == 0 {
*dst = CIDRArray{Status: Present}
} else {
elements := make([]CIDR, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = CIDRArray{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []CIDR:
if value == nil {
*dst = CIDRArray{Status: Null}
} else if len(value) == 0 {
*dst = CIDRArray{Status: Present}
} else {
*dst = CIDRArray{
Elements: value,
Dimensions: []ArrayDimension{{Length: int32(len(value)), LowerBound: 1}},
Status: Present,
}
}
default:
// Fallback to reflection if an optimised match was not found.
// The reflection is necessary for arrays and multidimensional slices,
// but it comes with a 20-50% performance penalty for large arrays/slices
reflectedValue := reflect.ValueOf(src)
if !reflectedValue.IsValid() || reflectedValue.IsZero() {
*dst = CIDRArray{Status: Null}
return nil
}
dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
if !ok {
return fmt.Errorf("cannot find dimensions of %v for CIDRArray", src)
}
if elementsLength == 0 {
*dst = CIDRArray{Status: Present}
return nil
}
if len(dimensions) == 0 {
if originalSrc, ok := underlyingSliceType(src); ok {
return dst.Set(originalSrc)
}
return fmt.Errorf("cannot convert %v to CIDRArray", src)
}
*dst = CIDRArray{
Elements: make([]CIDR, elementsLength),
Dimensions: dimensions,
Status: Present,
}
elementCount, err := dst.setRecursive(reflectedValue, 0, 0)
if err != nil {
// Maybe the target was one dimension too far, try again:
if len(dst.Dimensions) > 1 {
dst.Dimensions = dst.Dimensions[:len(dst.Dimensions)-1]
elementsLength = 0
for _, dim := range dst.Dimensions {
if elementsLength == 0 {
elementsLength = int(dim.Length)
} else {
elementsLength *= int(dim.Length)
}
}
dst.Elements = make([]CIDR, elementsLength)
elementCount, err = dst.setRecursive(reflectedValue, 0, 0)
if err != nil {
return err
}
} else {
return err
}
}
if elementCount != len(dst.Elements) {
return fmt.Errorf("cannot convert %v to CIDRArray, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
}
}
return nil
}
func (dst *CIDRArray) setRecursive(value reflect.Value, index, dimension int) (int, error) {
switch value.Kind() {
case reflect.Array:
fallthrough
case reflect.Slice:
if len(dst.Dimensions) == dimension {
break
}
valueLen := value.Len()
if int32(valueLen) != dst.Dimensions[dimension].Length {
return 0, fmt.Errorf("multidimensional arrays must have array expressions with matching dimensions")
}
for i := 0; i < valueLen; i++ {
var err error
index, err = dst.setRecursive(value.Index(i), index, dimension+1)
if err != nil {
return 0, err
}
}
return index, nil
}
if !value.CanInterface() {
return 0, fmt.Errorf("cannot convert all values to CIDRArray")
}
if err := dst.Elements[index].Set(value.Interface()); err != nil {
return 0, fmt.Errorf("%v in CIDRArray", err)
}
index++
return index, nil
}
func (dst CIDRArray) Get() interface{} {
switch dst.Status {
case Present:
return dst
case Null:
return nil
default:
return dst.Status
}
}
func (src *CIDRArray) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
if len(src.Dimensions) <= 1 {
// Attempt to match to select common types:
switch v := dst.(type) {
case *[]*net.IPNet:
*v = make([]*net.IPNet, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]net.IP:
*v = make([]net.IP, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]*net.IP:
*v = make([]*net.IP, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
}
}
// Try to convert to something AssignTo can use directly.
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
// Fallback to reflection if an optimised match was not found.
// The reflection is necessary for arrays and multidimensional slices,
// but it comes with a 20-50% performance penalty for large arrays/slices
value := reflect.ValueOf(dst)
if value.Kind() == reflect.Ptr {
value = value.Elem()
}
switch value.Kind() {
case reflect.Array, reflect.Slice:
default:
return fmt.Errorf("cannot assign %T to %T", src, dst)
}
if len(src.Elements) == 0 {
if value.Kind() == reflect.Slice {
value.Set(reflect.MakeSlice(value.Type(), 0, 0))
return nil
}
}
elementCount, err := src.assignToRecursive(value, 0, 0)
if err != nil {
return err
}
if elementCount != len(src.Elements) {
return fmt.Errorf("cannot assign %v, needed to assign %d elements, but only assigned %d", dst, len(src.Elements), elementCount)
}
return nil
case Null:
return NullAssignTo(dst)
}
return fmt.Errorf("cannot decode %#v into %T", src, dst)
}
func (src *CIDRArray) assignToRecursive(value reflect.Value, index, dimension int) (int, error) {
switch kind := value.Kind(); kind {
case reflect.Array:
fallthrough
case reflect.Slice:
if len(src.Dimensions) == dimension {
break
}
length := int(src.Dimensions[dimension].Length)
if reflect.Array == kind {
typ := value.Type()
if typ.Len() != length {
return 0, fmt.Errorf("expected size %d array, but %s has size %d array", length, typ, typ.Len())
}
value.Set(reflect.New(typ).Elem())
} else {
value.Set(reflect.MakeSlice(value.Type(), length, length))
}
var err error
for i := 0; i < length; i++ {
index, err = src.assignToRecursive(value.Index(i), index, dimension+1)
if err != nil {
return 0, err
}
}
return index, nil
}
if len(src.Dimensions) != dimension {
return 0, fmt.Errorf("incorrect dimensions, expected %d, found %d", len(src.Dimensions), dimension)
}
if !value.CanAddr() {
return 0, fmt.Errorf("cannot assign all values from CIDRArray")
}
addr := value.Addr()
if !addr.CanInterface() {
return 0, fmt.Errorf("cannot assign all values from CIDRArray")
}
if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
return 0, err
}
index++
return index, nil
}
func (dst *CIDRArray) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = CIDRArray{Status: Null}
return nil
}
uta, err := ParseUntypedTextArray(string(src))
if err != nil {
return err
}
var elements []CIDR
if len(uta.Elements) > 0 {
elements = make([]CIDR, len(uta.Elements))
for i, s := range uta.Elements {
var elem CIDR
var elemSrc []byte
if s != "NULL" || uta.Quoted[i] {
elemSrc = []byte(s)
}
err = elem.DecodeText(ci, elemSrc)
if err != nil {
return err
}
elements[i] = elem
}
}
*dst = CIDRArray{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
return nil
}
func (dst *CIDRArray) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = CIDRArray{Status: Null}
return nil
}
var arrayHeader ArrayHeader
rp, err := arrayHeader.DecodeBinary(ci, src)
if err != nil {
return err
}
if len(arrayHeader.Dimensions) == 0 {
*dst = CIDRArray{Dimensions: arrayHeader.Dimensions, Status: Present}
return nil
}
elementCount := arrayHeader.Dimensions[0].Length
for _, d := range arrayHeader.Dimensions[1:] {
elementCount *= d.Length
}
elements := make([]CIDR, elementCount)
for i := range elements {
elemLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
rp += 4
var elemSrc []byte
if elemLen >= 0 {
elemSrc = src[rp : rp+elemLen]
rp += elemLen
}
err = elements[i].DecodeBinary(ci, elemSrc)
if err != nil {
return err
}
}
*dst = CIDRArray{Elements: elements, Dimensions: arrayHeader.Dimensions, Status: Present}
return nil
}
func (src CIDRArray) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
if len(src.Dimensions) == 0 {
return append(buf, '{', '}'), nil
}
buf = EncodeTextArrayDimensions(buf, src.Dimensions)
// dimElemCounts is the multiples of elements that each array lies on. For
// example, a single dimension array of length 4 would have a dimElemCounts of
// [4]. A multi-dimensional array of lengths [3,5,2] would have a
// dimElemCounts of [30,10,2]. This is used to simplify when to render a '{'
// or '}'.
dimElemCounts := make([]int, len(src.Dimensions))
dimElemCounts[len(src.Dimensions)-1] = int(src.Dimensions[len(src.Dimensions)-1].Length)
for i := len(src.Dimensions) - 2; i > -1; i-- {
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
}
inElemBuf := make([]byte, 0, 32)
for i, elem := range src.Elements {
if i > 0 {
buf = append(buf, ',')
}
for _, dec := range dimElemCounts {
if i%dec == 0 {
buf = append(buf, '{')
}
}
elemBuf, err := elem.EncodeText(ci, inElemBuf)
if err != nil {
return nil, err
}
if elemBuf == nil {
buf = append(buf, `NULL`...)
} else {
buf = append(buf, QuoteArrayElementIfNeeded(string(elemBuf))...)
}
for _, dec := range dimElemCounts {
if (i+1)%dec == 0 {
buf = append(buf, '}')
}
}
}
return buf, nil
}
func (src CIDRArray) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
arrayHeader := ArrayHeader{
Dimensions: src.Dimensions,
}
if dt, ok := ci.DataTypeForName("cidr"); ok {
arrayHeader.ElementOID = int32(dt.OID)
} else {
return nil, fmt.Errorf("unable to find oid for type name %v", "cidr")
}
for i := range src.Elements {
if src.Elements[i].Status == Null {
arrayHeader.ContainsNull = true
break
}
}
buf = arrayHeader.EncodeBinary(ci, buf)
for i := range src.Elements {
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
elemBuf, err := src.Elements[i].EncodeBinary(ci, buf)
if err != nil {
return nil, err
}
if elemBuf != nil {
buf = elemBuf
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
}
return buf, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *CIDRArray) Scan(src interface{}) error {
if src == nil {
return dst.DecodeText(nil, nil)
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src CIDRArray) Value() (driver.Value, error) {
buf, err := src.EncodeText(nil, nil)
if err != nil {
return nil, err
}
if buf == nil {
return nil, nil
}
return string(buf), nil
}
-150
View File
@@ -1,150 +0,0 @@
package pgtype
import (
"database/sql/driver"
"encoding/binary"
"fmt"
"math"
"strconv"
"strings"
"github.com/jackc/pgio"
)
type Circle struct {
P Vec2
R float64
Status Status
}
func (dst *Circle) Set(src interface{}) error {
return fmt.Errorf("cannot convert %v to Circle", src)
}
func (dst Circle) Get() interface{} {
switch dst.Status {
case Present:
return dst
case Null:
return nil
default:
return dst.Status
}
}
func (src *Circle) AssignTo(dst interface{}) error {
return fmt.Errorf("cannot assign %v to %T", src, dst)
}
func (dst *Circle) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Circle{Status: Null}
return nil
}
if len(src) < 9 {
return fmt.Errorf("invalid length for Circle: %v", len(src))
}
str := string(src[2:])
end := strings.IndexByte(str, ',')
x, err := strconv.ParseFloat(str[:end], 64)
if err != nil {
return err
}
str = str[end+1:]
end = strings.IndexByte(str, ')')
y, err := strconv.ParseFloat(str[:end], 64)
if err != nil {
return err
}
str = str[end+2 : len(str)-1]
r, err := strconv.ParseFloat(str, 64)
if err != nil {
return err
}
*dst = Circle{P: Vec2{x, y}, R: r, Status: Present}
return nil
}
func (dst *Circle) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Circle{Status: Null}
return nil
}
if len(src) != 24 {
return fmt.Errorf("invalid length for Circle: %v", len(src))
}
x := binary.BigEndian.Uint64(src)
y := binary.BigEndian.Uint64(src[8:])
r := binary.BigEndian.Uint64(src[16:])
*dst = Circle{
P: Vec2{math.Float64frombits(x), math.Float64frombits(y)},
R: math.Float64frombits(r),
Status: Present,
}
return nil
}
func (src Circle) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
buf = append(buf, fmt.Sprintf(`<(%s,%s),%s>`,
strconv.FormatFloat(src.P.X, 'f', -1, 64),
strconv.FormatFloat(src.P.Y, 'f', -1, 64),
strconv.FormatFloat(src.R, 'f', -1, 64),
)...)
return buf, nil
}
func (src Circle) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
buf = pgio.AppendUint64(buf, math.Float64bits(src.P.X))
buf = pgio.AppendUint64(buf, math.Float64bits(src.P.Y))
buf = pgio.AppendUint64(buf, math.Float64bits(src.R))
return buf, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *Circle) Scan(src interface{}) error {
if src == nil {
*dst = Circle{Status: Null}
return nil
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src Circle) Value() (driver.Value, error) {
return EncodeValueText(src)
}
-107
View File
@@ -1,107 +0,0 @@
package pgtype
import "fmt"
// CompositeFields scans the fields of a composite type into the elements of the CompositeFields value. To scan a
// nullable value use a *CompositeFields. It will be set to nil in case of null.
//
// CompositeFields implements EncodeBinary and EncodeText. However, functionality is limited due to CompositeFields not
// knowing the PostgreSQL schema of the composite type. Prefer using a registered CompositeType.
type CompositeFields []interface{}
func (cf CompositeFields) DecodeBinary(ci *ConnInfo, src []byte) error {
if len(cf) == 0 {
return fmt.Errorf("cannot decode into empty CompositeFields")
}
if src == nil {
return fmt.Errorf("cannot decode unexpected null into CompositeFields")
}
scanner := NewCompositeBinaryScanner(ci, src)
for _, f := range cf {
scanner.ScanValue(f)
}
if scanner.Err() != nil {
return scanner.Err()
}
return nil
}
func (cf CompositeFields) DecodeText(ci *ConnInfo, src []byte) error {
if len(cf) == 0 {
return fmt.Errorf("cannot decode into empty CompositeFields")
}
if src == nil {
return fmt.Errorf("cannot decode unexpected null into CompositeFields")
}
scanner := NewCompositeTextScanner(ci, src)
for _, f := range cf {
scanner.ScanValue(f)
}
if scanner.Err() != nil {
return scanner.Err()
}
return nil
}
// EncodeText encodes composite fields into the text format. Prefer registering a CompositeType to using
// CompositeFields to encode directly.
func (cf CompositeFields) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
b := NewCompositeTextBuilder(ci, buf)
for _, f := range cf {
if textEncoder, ok := f.(TextEncoder); ok {
b.AppendEncoder(textEncoder)
} else {
b.AppendValue(f)
}
}
return b.Finish()
}
// EncodeBinary encodes composite fields into the binary format. Unlike CompositeType the schema of the destination is
// unknown. Prefer registering a CompositeType to using CompositeFields to encode directly. Because the binary
// composite format requires the OID of each field to be specified the only types that will work are those known to
// ConnInfo.
//
// In particular:
//
// * Nil cannot be used because there is no way to determine what type it.
// * Integer types must be exact matches. e.g. A Go int32 into a PostgreSQL bigint will fail.
// * No dereferencing will be done. e.g. *Text must be used instead of Text.
func (cf CompositeFields) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
b := NewCompositeBinaryBuilder(ci, buf)
for _, f := range cf {
dt, ok := ci.DataTypeForValue(f)
if !ok {
return nil, fmt.Errorf("Unknown OID for %#v", f)
}
if binaryEncoder, ok := f.(BinaryEncoder); ok {
b.AppendEncoder(dt.OID, binaryEncoder)
} else {
err := dt.Value.Set(f)
if err != nil {
return nil, err
}
if binaryEncoder, ok := dt.Value.(BinaryEncoder); ok {
b.AppendEncoder(dt.OID, binaryEncoder)
} else {
return nil, fmt.Errorf("Cannot encode binary format for %v", f)
}
}
}
return b.Finish()
}
-682
View File
@@ -1,682 +0,0 @@
package pgtype
import (
"encoding/binary"
"errors"
"fmt"
"reflect"
"strings"
"github.com/jackc/pgio"
)
type CompositeTypeField struct {
Name string
OID uint32
}
type CompositeType struct {
status Status
typeName string
fields []CompositeTypeField
valueTranscoders []ValueTranscoder
}
// NewCompositeType creates a CompositeType from fields and ci. ci is used to find the ValueTranscoders used
// for fields. All field OIDs must be previously registered in ci.
func NewCompositeType(typeName string, fields []CompositeTypeField, ci *ConnInfo) (*CompositeType, error) {
valueTranscoders := make([]ValueTranscoder, len(fields))
for i := range fields {
dt, ok := ci.DataTypeForOID(fields[i].OID)
if !ok {
return nil, fmt.Errorf("no data type registered for oid: %d", fields[i].OID)
}
value := NewValue(dt.Value)
valueTranscoder, ok := value.(ValueTranscoder)
if !ok {
return nil, fmt.Errorf("data type for oid does not implement ValueTranscoder: %d", fields[i].OID)
}
valueTranscoders[i] = valueTranscoder
}
return &CompositeType{typeName: typeName, fields: fields, valueTranscoders: valueTranscoders}, nil
}
// NewCompositeTypeValues creates a CompositeType from fields and values. fields and values must have the same length.
// Prefer NewCompositeType unless overriding the transcoding of fields is required.
func NewCompositeTypeValues(typeName string, fields []CompositeTypeField, values []ValueTranscoder) (*CompositeType, error) {
if len(fields) != len(values) {
return nil, errors.New("fields and valueTranscoders must have same length")
}
return &CompositeType{typeName: typeName, fields: fields, valueTranscoders: values}, nil
}
func (src CompositeType) Get() interface{} {
switch src.status {
case Present:
results := make(map[string]interface{}, len(src.valueTranscoders))
for i := range src.valueTranscoders {
results[src.fields[i].Name] = src.valueTranscoders[i].Get()
}
return results
case Null:
return nil
default:
return src.status
}
}
func (ct *CompositeType) NewTypeValue() Value {
a := &CompositeType{
typeName: ct.typeName,
fields: ct.fields,
valueTranscoders: make([]ValueTranscoder, len(ct.valueTranscoders)),
}
for i := range ct.valueTranscoders {
a.valueTranscoders[i] = NewValue(ct.valueTranscoders[i]).(ValueTranscoder)
}
return a
}
func (ct *CompositeType) TypeName() string {
return ct.typeName
}
func (ct *CompositeType) Fields() []CompositeTypeField {
return ct.fields
}
func (dst *CompositeType) Set(src interface{}) error {
if src == nil {
dst.status = Null
return nil
}
switch value := src.(type) {
case []interface{}:
if len(value) != len(dst.valueTranscoders) {
return fmt.Errorf("Number of fields don't match. CompositeType has %d fields", len(dst.valueTranscoders))
}
for i, v := range value {
if err := dst.valueTranscoders[i].Set(v); err != nil {
return err
}
}
dst.status = Present
case *[]interface{}:
if value == nil {
dst.status = Null
return nil
}
return dst.Set(*value)
default:
return fmt.Errorf("Can not convert %v to Composite", src)
}
return nil
}
// AssignTo should never be called on composite value directly
func (src CompositeType) AssignTo(dst interface{}) error {
switch src.status {
case Present:
switch v := dst.(type) {
case []interface{}:
if len(v) != len(src.valueTranscoders) {
return fmt.Errorf("Number of fields don't match. CompositeType has %d fields", len(src.valueTranscoders))
}
for i := range src.valueTranscoders {
if v[i] == nil {
continue
}
err := assignToOrSet(src.valueTranscoders[i], v[i])
if err != nil {
return fmt.Errorf("unable to assign to dst[%d]: %v", i, err)
}
}
return nil
case *[]interface{}:
return src.AssignTo(*v)
default:
if isPtrStruct, err := src.assignToPtrStruct(dst); isPtrStruct {
return err
}
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
return fmt.Errorf("unable to assign to %T", dst)
}
case Null:
return NullAssignTo(dst)
}
return fmt.Errorf("cannot decode %#v into %T", src, dst)
}
func assignToOrSet(src Value, dst interface{}) error {
assignToErr := src.AssignTo(dst)
if assignToErr != nil {
// Try to use get / set instead -- this avoids every type having to be able to AssignTo type of self.
setSucceeded := false
if setter, ok := dst.(Value); ok {
err := setter.Set(src.Get())
setSucceeded = err == nil
}
if !setSucceeded {
return assignToErr
}
}
return nil
}
func (src CompositeType) assignToPtrStruct(dst interface{}) (bool, error) {
dstValue := reflect.ValueOf(dst)
if dstValue.Kind() != reflect.Ptr {
return false, nil
}
if dstValue.IsNil() {
return false, nil
}
dstElemValue := dstValue.Elem()
dstElemType := dstElemValue.Type()
if dstElemType.Kind() != reflect.Struct {
return false, nil
}
exportedFields := make([]int, 0, dstElemType.NumField())
for i := 0; i < dstElemType.NumField(); i++ {
sf := dstElemType.Field(i)
if sf.PkgPath == "" {
exportedFields = append(exportedFields, i)
}
}
if len(exportedFields) != len(src.valueTranscoders) {
return false, nil
}
for i := range exportedFields {
err := assignToOrSet(src.valueTranscoders[i], dstElemValue.Field(exportedFields[i]).Addr().Interface())
if err != nil {
return true, fmt.Errorf("unable to assign to field %s: %v", dstElemType.Field(exportedFields[i]).Name, err)
}
}
return true, nil
}
func (src CompositeType) EncodeBinary(ci *ConnInfo, buf []byte) (newBuf []byte, err error) {
switch src.status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
b := NewCompositeBinaryBuilder(ci, buf)
for i := range src.valueTranscoders {
b.AppendEncoder(src.fields[i].OID, src.valueTranscoders[i])
}
return b.Finish()
}
// DecodeBinary implements BinaryDecoder interface.
// Opposite to Record, fields in a composite act as a "schema"
// and decoding fails if SQL value can't be assigned due to
// type mismatch
func (dst *CompositeType) DecodeBinary(ci *ConnInfo, buf []byte) error {
if buf == nil {
dst.status = Null
return nil
}
scanner := NewCompositeBinaryScanner(ci, buf)
for _, f := range dst.valueTranscoders {
scanner.ScanDecoder(f)
}
if scanner.Err() != nil {
return scanner.Err()
}
dst.status = Present
return nil
}
func (dst *CompositeType) DecodeText(ci *ConnInfo, buf []byte) error {
if buf == nil {
dst.status = Null
return nil
}
scanner := NewCompositeTextScanner(ci, buf)
for _, f := range dst.valueTranscoders {
scanner.ScanDecoder(f)
}
if scanner.Err() != nil {
return scanner.Err()
}
dst.status = Present
return nil
}
func (src CompositeType) EncodeText(ci *ConnInfo, buf []byte) (newBuf []byte, err error) {
switch src.status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
b := NewCompositeTextBuilder(ci, buf)
for _, f := range src.valueTranscoders {
b.AppendEncoder(f)
}
return b.Finish()
}
type CompositeBinaryScanner struct {
ci *ConnInfo
rp int
src []byte
fieldCount int32
fieldBytes []byte
fieldOID uint32
err error
}
// NewCompositeBinaryScanner a scanner over a binary encoded composite balue.
func NewCompositeBinaryScanner(ci *ConnInfo, src []byte) *CompositeBinaryScanner {
rp := 0
if len(src[rp:]) < 4 {
return &CompositeBinaryScanner{err: fmt.Errorf("Record incomplete %v", src)}
}
fieldCount := int32(binary.BigEndian.Uint32(src[rp:]))
rp += 4
return &CompositeBinaryScanner{
ci: ci,
rp: rp,
src: src,
fieldCount: fieldCount,
}
}
// ScanDecoder calls Next and decodes the result with d.
func (cfs *CompositeBinaryScanner) ScanDecoder(d BinaryDecoder) {
if cfs.err != nil {
return
}
if cfs.Next() {
cfs.err = d.DecodeBinary(cfs.ci, cfs.fieldBytes)
} else {
cfs.err = errors.New("read past end of composite")
}
}
// ScanDecoder calls Next and scans the result into d.
func (cfs *CompositeBinaryScanner) ScanValue(d interface{}) {
if cfs.err != nil {
return
}
if cfs.Next() {
cfs.err = cfs.ci.Scan(cfs.OID(), BinaryFormatCode, cfs.Bytes(), d)
} else {
cfs.err = errors.New("read past end of composite")
}
}
// Next advances the scanner to the next field. It returns false after the last field is read or an error occurs. After
// Next returns false, the Err method can be called to check if any errors occurred.
func (cfs *CompositeBinaryScanner) Next() bool {
if cfs.err != nil {
return false
}
if cfs.rp == len(cfs.src) {
return false
}
if len(cfs.src[cfs.rp:]) < 8 {
cfs.err = fmt.Errorf("Record incomplete %v", cfs.src)
return false
}
cfs.fieldOID = binary.BigEndian.Uint32(cfs.src[cfs.rp:])
cfs.rp += 4
fieldLen := int(int32(binary.BigEndian.Uint32(cfs.src[cfs.rp:])))
cfs.rp += 4
if fieldLen >= 0 {
if len(cfs.src[cfs.rp:]) < fieldLen {
cfs.err = fmt.Errorf("Record incomplete rp=%d src=%v", cfs.rp, cfs.src)
return false
}
cfs.fieldBytes = cfs.src[cfs.rp : cfs.rp+fieldLen]
cfs.rp += fieldLen
} else {
cfs.fieldBytes = nil
}
return true
}
func (cfs *CompositeBinaryScanner) FieldCount() int {
return int(cfs.fieldCount)
}
// Bytes returns the bytes of the field most recently read by Scan().
func (cfs *CompositeBinaryScanner) Bytes() []byte {
return cfs.fieldBytes
}
// OID returns the OID of the field most recently read by Scan().
func (cfs *CompositeBinaryScanner) OID() uint32 {
return cfs.fieldOID
}
// Err returns any error encountered by the scanner.
func (cfs *CompositeBinaryScanner) Err() error {
return cfs.err
}
type CompositeTextScanner struct {
ci *ConnInfo
rp int
src []byte
fieldBytes []byte
err error
}
// NewCompositeTextScanner a scanner over a text encoded composite value.
func NewCompositeTextScanner(ci *ConnInfo, src []byte) *CompositeTextScanner {
if len(src) < 2 {
return &CompositeTextScanner{err: fmt.Errorf("Record incomplete %v", src)}
}
if src[0] != '(' {
return &CompositeTextScanner{err: fmt.Errorf("composite text format must start with '('")}
}
if src[len(src)-1] != ')' {
return &CompositeTextScanner{err: fmt.Errorf("composite text format must end with ')'")}
}
return &CompositeTextScanner{
ci: ci,
rp: 1,
src: src,
}
}
// ScanDecoder calls Next and decodes the result with d.
func (cfs *CompositeTextScanner) ScanDecoder(d TextDecoder) {
if cfs.err != nil {
return
}
if cfs.Next() {
cfs.err = d.DecodeText(cfs.ci, cfs.fieldBytes)
} else {
cfs.err = errors.New("read past end of composite")
}
}
// ScanDecoder calls Next and scans the result into d.
func (cfs *CompositeTextScanner) ScanValue(d interface{}) {
if cfs.err != nil {
return
}
if cfs.Next() {
cfs.err = cfs.ci.Scan(0, TextFormatCode, cfs.Bytes(), d)
} else {
cfs.err = errors.New("read past end of composite")
}
}
// Next advances the scanner to the next field. It returns false after the last field is read or an error occurs. After
// Next returns false, the Err method can be called to check if any errors occurred.
func (cfs *CompositeTextScanner) Next() bool {
if cfs.err != nil {
return false
}
if cfs.rp == len(cfs.src) {
return false
}
switch cfs.src[cfs.rp] {
case ',', ')': // null
cfs.rp++
cfs.fieldBytes = nil
return true
case '"': // quoted value
cfs.rp++
cfs.fieldBytes = make([]byte, 0, 16)
for {
ch := cfs.src[cfs.rp]
if ch == '"' {
cfs.rp++
if cfs.src[cfs.rp] == '"' {
cfs.fieldBytes = append(cfs.fieldBytes, '"')
cfs.rp++
} else {
break
}
} else if ch == '\\' {
cfs.rp++
cfs.fieldBytes = append(cfs.fieldBytes, cfs.src[cfs.rp])
cfs.rp++
} else {
cfs.fieldBytes = append(cfs.fieldBytes, ch)
cfs.rp++
}
}
cfs.rp++
return true
default: // unquoted value
start := cfs.rp
for {
ch := cfs.src[cfs.rp]
if ch == ',' || ch == ')' {
break
}
cfs.rp++
}
cfs.fieldBytes = cfs.src[start:cfs.rp]
cfs.rp++
return true
}
}
// Bytes returns the bytes of the field most recently read by Scan().
func (cfs *CompositeTextScanner) Bytes() []byte {
return cfs.fieldBytes
}
// Err returns any error encountered by the scanner.
func (cfs *CompositeTextScanner) Err() error {
return cfs.err
}
type CompositeBinaryBuilder struct {
ci *ConnInfo
buf []byte
startIdx int
fieldCount uint32
err error
}
func NewCompositeBinaryBuilder(ci *ConnInfo, buf []byte) *CompositeBinaryBuilder {
startIdx := len(buf)
buf = append(buf, 0, 0, 0, 0) // allocate room for number of fields
return &CompositeBinaryBuilder{ci: ci, buf: buf, startIdx: startIdx}
}
func (b *CompositeBinaryBuilder) AppendValue(oid uint32, field interface{}) {
if b.err != nil {
return
}
dt, ok := b.ci.DataTypeForOID(oid)
if !ok {
b.err = fmt.Errorf("unknown data type for OID: %d", oid)
return
}
err := dt.Value.Set(field)
if err != nil {
b.err = err
return
}
binaryEncoder, ok := dt.Value.(BinaryEncoder)
if !ok {
b.err = fmt.Errorf("unable to encode binary for OID: %d", oid)
return
}
b.AppendEncoder(oid, binaryEncoder)
}
func (b *CompositeBinaryBuilder) AppendEncoder(oid uint32, field BinaryEncoder) {
if b.err != nil {
return
}
b.buf = pgio.AppendUint32(b.buf, oid)
lengthPos := len(b.buf)
b.buf = pgio.AppendInt32(b.buf, -1)
fieldBuf, err := field.EncodeBinary(b.ci, b.buf)
if err != nil {
b.err = err
return
}
if fieldBuf != nil {
binary.BigEndian.PutUint32(fieldBuf[lengthPos:], uint32(len(fieldBuf)-len(b.buf)))
b.buf = fieldBuf
}
b.fieldCount++
}
func (b *CompositeBinaryBuilder) Finish() ([]byte, error) {
if b.err != nil {
return nil, b.err
}
binary.BigEndian.PutUint32(b.buf[b.startIdx:], b.fieldCount)
return b.buf, nil
}
type CompositeTextBuilder struct {
ci *ConnInfo
buf []byte
startIdx int
fieldCount uint32
err error
fieldBuf [32]byte
}
func NewCompositeTextBuilder(ci *ConnInfo, buf []byte) *CompositeTextBuilder {
buf = append(buf, '(') // allocate room for number of fields
return &CompositeTextBuilder{ci: ci, buf: buf}
}
func (b *CompositeTextBuilder) AppendValue(field interface{}) {
if b.err != nil {
return
}
if field == nil {
b.buf = append(b.buf, ',')
return
}
dt, ok := b.ci.DataTypeForValue(field)
if !ok {
b.err = fmt.Errorf("unknown data type for field: %v", field)
return
}
err := dt.Value.Set(field)
if err != nil {
b.err = err
return
}
textEncoder, ok := dt.Value.(TextEncoder)
if !ok {
b.err = fmt.Errorf("unable to encode text for value: %v", field)
return
}
b.AppendEncoder(textEncoder)
}
func (b *CompositeTextBuilder) AppendEncoder(field TextEncoder) {
if b.err != nil {
return
}
fieldBuf, err := field.EncodeText(b.ci, b.fieldBuf[0:0])
if err != nil {
b.err = err
return
}
if fieldBuf != nil {
b.buf = append(b.buf, quoteCompositeFieldIfNeeded(string(fieldBuf))...)
}
b.buf = append(b.buf, ',')
}
func (b *CompositeTextBuilder) Finish() ([]byte, error) {
if b.err != nil {
return nil, b.err
}
b.buf[len(b.buf)-1] = ')'
return b.buf, nil
}
var quoteCompositeReplacer = strings.NewReplacer(`\`, `\\`, `"`, `\"`)
func quoteCompositeField(src string) string {
return `"` + quoteCompositeReplacer.Replace(src) + `"`
}
func quoteCompositeFieldIfNeeded(src string) string {
if src == "" || src[0] == ' ' || src[len(src)-1] == ' ' || strings.ContainsAny(src, `(),"\`) {
return quoteCompositeField(src)
}
return src
}
-41
View File
@@ -1,41 +0,0 @@
package pgtype
import (
"database/sql/driver"
"errors"
)
func DatabaseSQLValue(ci *ConnInfo, src Value) (interface{}, error) {
if valuer, ok := src.(driver.Valuer); ok {
return valuer.Value()
}
if textEncoder, ok := src.(TextEncoder); ok {
buf, err := textEncoder.EncodeText(ci, nil)
if err != nil {
return nil, err
}
return string(buf), nil
}
if binaryEncoder, ok := src.(BinaryEncoder); ok {
buf, err := binaryEncoder.EncodeBinary(ci, nil)
if err != nil {
return nil, err
}
return buf, nil
}
return nil, errors.New("cannot convert to database/sql compatible value")
}
func EncodeValueText(src TextEncoder) (interface{}, error) {
buf, err := src.EncodeText(nil, make([]byte, 0, 32))
if err != nil {
return nil, err
}
if buf == nil {
return nil, nil
}
return string(buf), err
}
-287
View File
@@ -1,287 +0,0 @@
package pgtype
import (
"database/sql/driver"
"encoding/binary"
"encoding/json"
"fmt"
"time"
"github.com/jackc/pgio"
)
type Date struct {
Time time.Time
Status Status
InfinityModifier InfinityModifier
}
const (
negativeInfinityDayOffset = -2147483648
infinityDayOffset = 2147483647
)
func (dst *Date) Set(src interface{}) error {
if src == nil {
*dst = Date{Status: Null}
return nil
}
if value, ok := src.(interface{ Get() interface{} }); ok {
value2 := value.Get()
if value2 != value {
return dst.Set(value2)
}
}
switch value := src.(type) {
case time.Time:
*dst = Date{Time: value, Status: Present}
case *time.Time:
if value == nil {
*dst = Date{Status: Null}
} else {
return dst.Set(*value)
}
case string:
return dst.DecodeText(nil, []byte(value))
case *string:
if value == nil {
*dst = Date{Status: Null}
} else {
return dst.Set(*value)
}
default:
if originalSrc, ok := underlyingTimeType(src); ok {
return dst.Set(originalSrc)
}
return fmt.Errorf("cannot convert %v to Date", value)
}
return nil
}
func (dst Date) Get() interface{} {
switch dst.Status {
case Present:
if dst.InfinityModifier != None {
return dst.InfinityModifier
}
return dst.Time
case Null:
return nil
default:
return dst.Status
}
}
func (src *Date) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
switch v := dst.(type) {
case *time.Time:
if src.InfinityModifier != None {
return fmt.Errorf("cannot assign %v to %T", src, dst)
}
*v = src.Time
return nil
default:
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
return fmt.Errorf("unable to assign to %T", dst)
}
case Null:
return NullAssignTo(dst)
}
return fmt.Errorf("cannot decode %#v into %T", src, dst)
}
func (dst *Date) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Date{Status: Null}
return nil
}
sbuf := string(src)
switch sbuf {
case "infinity":
*dst = Date{Status: Present, InfinityModifier: Infinity}
case "-infinity":
*dst = Date{Status: Present, InfinityModifier: -Infinity}
default:
t, err := time.ParseInLocation("2006-01-02", sbuf, time.UTC)
if err != nil {
return err
}
*dst = Date{Time: t, Status: Present}
}
return nil
}
func (dst *Date) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Date{Status: Null}
return nil
}
if len(src) != 4 {
return fmt.Errorf("invalid length for date: %v", len(src))
}
dayOffset := int32(binary.BigEndian.Uint32(src))
switch dayOffset {
case infinityDayOffset:
*dst = Date{Status: Present, InfinityModifier: Infinity}
case negativeInfinityDayOffset:
*dst = Date{Status: Present, InfinityModifier: -Infinity}
default:
t := time.Date(2000, 1, int(1+dayOffset), 0, 0, 0, 0, time.UTC)
*dst = Date{Time: t, Status: Present}
}
return nil
}
func (src Date) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
var s string
switch src.InfinityModifier {
case None:
s = src.Time.Format("2006-01-02")
case Infinity:
s = "infinity"
case NegativeInfinity:
s = "-infinity"
}
return append(buf, s...), nil
}
func (src Date) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
var daysSinceDateEpoch int32
switch src.InfinityModifier {
case None:
tUnix := time.Date(src.Time.Year(), src.Time.Month(), src.Time.Day(), 0, 0, 0, 0, time.UTC).Unix()
dateEpoch := time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC).Unix()
secSinceDateEpoch := tUnix - dateEpoch
daysSinceDateEpoch = int32(secSinceDateEpoch / 86400)
case Infinity:
daysSinceDateEpoch = infinityDayOffset
case NegativeInfinity:
daysSinceDateEpoch = negativeInfinityDayOffset
}
return pgio.AppendInt32(buf, daysSinceDateEpoch), nil
}
// Scan implements the database/sql Scanner interface.
func (dst *Date) Scan(src interface{}) error {
if src == nil {
*dst = Date{Status: Null}
return nil
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
case time.Time:
*dst = Date{Time: src, Status: Present}
return nil
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src Date) Value() (driver.Value, error) {
switch src.Status {
case Present:
if src.InfinityModifier != None {
return src.InfinityModifier.String(), nil
}
return src.Time, nil
case Null:
return nil, nil
default:
return nil, errUndefined
}
}
func (src Date) MarshalJSON() ([]byte, error) {
switch src.Status {
case Null:
return []byte("null"), nil
case Undefined:
return nil, errUndefined
}
if src.Status != Present {
return nil, errBadStatus
}
var s string
switch src.InfinityModifier {
case None:
s = src.Time.Format("2006-01-02")
case Infinity:
s = "infinity"
case NegativeInfinity:
s = "-infinity"
}
return json.Marshal(s)
}
func (dst *Date) UnmarshalJSON(b []byte) error {
var s *string
err := json.Unmarshal(b, &s)
if err != nil {
return err
}
if s == nil {
*dst = Date{Status: Null}
return nil
}
switch *s {
case "infinity":
*dst = Date{Status: Present, InfinityModifier: Infinity}
case "-infinity":
*dst = Date{Status: Present, InfinityModifier: -Infinity}
default:
t, err := time.ParseInLocation("2006-01-02", *s, time.UTC)
if err != nil {
return err
}
*dst = Date{Time: t, Status: Present}
}
return nil
}
-518
View File
@@ -1,518 +0,0 @@
// Code generated by erb. DO NOT EDIT.
package pgtype
import (
"database/sql/driver"
"encoding/binary"
"fmt"
"reflect"
"time"
"github.com/jackc/pgio"
)
type DateArray struct {
Elements []Date
Dimensions []ArrayDimension
Status Status
}
func (dst *DateArray) Set(src interface{}) error {
// untyped nil and typed nil interfaces are different
if src == nil {
*dst = DateArray{Status: Null}
return nil
}
if value, ok := src.(interface{ Get() interface{} }); ok {
value2 := value.Get()
if value2 != value {
return dst.Set(value2)
}
}
// Attempt to match to select common types:
switch value := src.(type) {
case []time.Time:
if value == nil {
*dst = DateArray{Status: Null}
} else if len(value) == 0 {
*dst = DateArray{Status: Present}
} else {
elements := make([]Date, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = DateArray{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []*time.Time:
if value == nil {
*dst = DateArray{Status: Null}
} else if len(value) == 0 {
*dst = DateArray{Status: Present}
} else {
elements := make([]Date, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = DateArray{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []Date:
if value == nil {
*dst = DateArray{Status: Null}
} else if len(value) == 0 {
*dst = DateArray{Status: Present}
} else {
*dst = DateArray{
Elements: value,
Dimensions: []ArrayDimension{{Length: int32(len(value)), LowerBound: 1}},
Status: Present,
}
}
default:
// Fallback to reflection if an optimised match was not found.
// The reflection is necessary for arrays and multidimensional slices,
// but it comes with a 20-50% performance penalty for large arrays/slices
reflectedValue := reflect.ValueOf(src)
if !reflectedValue.IsValid() || reflectedValue.IsZero() {
*dst = DateArray{Status: Null}
return nil
}
dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
if !ok {
return fmt.Errorf("cannot find dimensions of %v for DateArray", src)
}
if elementsLength == 0 {
*dst = DateArray{Status: Present}
return nil
}
if len(dimensions) == 0 {
if originalSrc, ok := underlyingSliceType(src); ok {
return dst.Set(originalSrc)
}
return fmt.Errorf("cannot convert %v to DateArray", src)
}
*dst = DateArray{
Elements: make([]Date, elementsLength),
Dimensions: dimensions,
Status: Present,
}
elementCount, err := dst.setRecursive(reflectedValue, 0, 0)
if err != nil {
// Maybe the target was one dimension too far, try again:
if len(dst.Dimensions) > 1 {
dst.Dimensions = dst.Dimensions[:len(dst.Dimensions)-1]
elementsLength = 0
for _, dim := range dst.Dimensions {
if elementsLength == 0 {
elementsLength = int(dim.Length)
} else {
elementsLength *= int(dim.Length)
}
}
dst.Elements = make([]Date, elementsLength)
elementCount, err = dst.setRecursive(reflectedValue, 0, 0)
if err != nil {
return err
}
} else {
return err
}
}
if elementCount != len(dst.Elements) {
return fmt.Errorf("cannot convert %v to DateArray, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
}
}
return nil
}
func (dst *DateArray) setRecursive(value reflect.Value, index, dimension int) (int, error) {
switch value.Kind() {
case reflect.Array:
fallthrough
case reflect.Slice:
if len(dst.Dimensions) == dimension {
break
}
valueLen := value.Len()
if int32(valueLen) != dst.Dimensions[dimension].Length {
return 0, fmt.Errorf("multidimensional arrays must have array expressions with matching dimensions")
}
for i := 0; i < valueLen; i++ {
var err error
index, err = dst.setRecursive(value.Index(i), index, dimension+1)
if err != nil {
return 0, err
}
}
return index, nil
}
if !value.CanInterface() {
return 0, fmt.Errorf("cannot convert all values to DateArray")
}
if err := dst.Elements[index].Set(value.Interface()); err != nil {
return 0, fmt.Errorf("%v in DateArray", err)
}
index++
return index, nil
}
func (dst DateArray) Get() interface{} {
switch dst.Status {
case Present:
return dst
case Null:
return nil
default:
return dst.Status
}
}
func (src *DateArray) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
if len(src.Dimensions) <= 1 {
// Attempt to match to select common types:
switch v := dst.(type) {
case *[]time.Time:
*v = make([]time.Time, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]*time.Time:
*v = make([]*time.Time, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
}
}
// Try to convert to something AssignTo can use directly.
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
// Fallback to reflection if an optimised match was not found.
// The reflection is necessary for arrays and multidimensional slices,
// but it comes with a 20-50% performance penalty for large arrays/slices
value := reflect.ValueOf(dst)
if value.Kind() == reflect.Ptr {
value = value.Elem()
}
switch value.Kind() {
case reflect.Array, reflect.Slice:
default:
return fmt.Errorf("cannot assign %T to %T", src, dst)
}
if len(src.Elements) == 0 {
if value.Kind() == reflect.Slice {
value.Set(reflect.MakeSlice(value.Type(), 0, 0))
return nil
}
}
elementCount, err := src.assignToRecursive(value, 0, 0)
if err != nil {
return err
}
if elementCount != len(src.Elements) {
return fmt.Errorf("cannot assign %v, needed to assign %d elements, but only assigned %d", dst, len(src.Elements), elementCount)
}
return nil
case Null:
return NullAssignTo(dst)
}
return fmt.Errorf("cannot decode %#v into %T", src, dst)
}
func (src *DateArray) assignToRecursive(value reflect.Value, index, dimension int) (int, error) {
switch kind := value.Kind(); kind {
case reflect.Array:
fallthrough
case reflect.Slice:
if len(src.Dimensions) == dimension {
break
}
length := int(src.Dimensions[dimension].Length)
if reflect.Array == kind {
typ := value.Type()
if typ.Len() != length {
return 0, fmt.Errorf("expected size %d array, but %s has size %d array", length, typ, typ.Len())
}
value.Set(reflect.New(typ).Elem())
} else {
value.Set(reflect.MakeSlice(value.Type(), length, length))
}
var err error
for i := 0; i < length; i++ {
index, err = src.assignToRecursive(value.Index(i), index, dimension+1)
if err != nil {
return 0, err
}
}
return index, nil
}
if len(src.Dimensions) != dimension {
return 0, fmt.Errorf("incorrect dimensions, expected %d, found %d", len(src.Dimensions), dimension)
}
if !value.CanAddr() {
return 0, fmt.Errorf("cannot assign all values from DateArray")
}
addr := value.Addr()
if !addr.CanInterface() {
return 0, fmt.Errorf("cannot assign all values from DateArray")
}
if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
return 0, err
}
index++
return index, nil
}
func (dst *DateArray) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = DateArray{Status: Null}
return nil
}
uta, err := ParseUntypedTextArray(string(src))
if err != nil {
return err
}
var elements []Date
if len(uta.Elements) > 0 {
elements = make([]Date, len(uta.Elements))
for i, s := range uta.Elements {
var elem Date
var elemSrc []byte
if s != "NULL" || uta.Quoted[i] {
elemSrc = []byte(s)
}
err = elem.DecodeText(ci, elemSrc)
if err != nil {
return err
}
elements[i] = elem
}
}
*dst = DateArray{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
return nil
}
func (dst *DateArray) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = DateArray{Status: Null}
return nil
}
var arrayHeader ArrayHeader
rp, err := arrayHeader.DecodeBinary(ci, src)
if err != nil {
return err
}
if len(arrayHeader.Dimensions) == 0 {
*dst = DateArray{Dimensions: arrayHeader.Dimensions, Status: Present}
return nil
}
elementCount := arrayHeader.Dimensions[0].Length
for _, d := range arrayHeader.Dimensions[1:] {
elementCount *= d.Length
}
elements := make([]Date, elementCount)
for i := range elements {
elemLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
rp += 4
var elemSrc []byte
if elemLen >= 0 {
elemSrc = src[rp : rp+elemLen]
rp += elemLen
}
err = elements[i].DecodeBinary(ci, elemSrc)
if err != nil {
return err
}
}
*dst = DateArray{Elements: elements, Dimensions: arrayHeader.Dimensions, Status: Present}
return nil
}
func (src DateArray) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
if len(src.Dimensions) == 0 {
return append(buf, '{', '}'), nil
}
buf = EncodeTextArrayDimensions(buf, src.Dimensions)
// dimElemCounts is the multiples of elements that each array lies on. For
// example, a single dimension array of length 4 would have a dimElemCounts of
// [4]. A multi-dimensional array of lengths [3,5,2] would have a
// dimElemCounts of [30,10,2]. This is used to simplify when to render a '{'
// or '}'.
dimElemCounts := make([]int, len(src.Dimensions))
dimElemCounts[len(src.Dimensions)-1] = int(src.Dimensions[len(src.Dimensions)-1].Length)
for i := len(src.Dimensions) - 2; i > -1; i-- {
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
}
inElemBuf := make([]byte, 0, 32)
for i, elem := range src.Elements {
if i > 0 {
buf = append(buf, ',')
}
for _, dec := range dimElemCounts {
if i%dec == 0 {
buf = append(buf, '{')
}
}
elemBuf, err := elem.EncodeText(ci, inElemBuf)
if err != nil {
return nil, err
}
if elemBuf == nil {
buf = append(buf, `NULL`...)
} else {
buf = append(buf, QuoteArrayElementIfNeeded(string(elemBuf))...)
}
for _, dec := range dimElemCounts {
if (i+1)%dec == 0 {
buf = append(buf, '}')
}
}
}
return buf, nil
}
func (src DateArray) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
arrayHeader := ArrayHeader{
Dimensions: src.Dimensions,
}
if dt, ok := ci.DataTypeForName("date"); ok {
arrayHeader.ElementOID = int32(dt.OID)
} else {
return nil, fmt.Errorf("unable to find oid for type name %v", "date")
}
for i := range src.Elements {
if src.Elements[i].Status == Null {
arrayHeader.ContainsNull = true
break
}
}
buf = arrayHeader.EncodeBinary(ci, buf)
for i := range src.Elements {
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
elemBuf, err := src.Elements[i].EncodeBinary(ci, buf)
if err != nil {
return nil, err
}
if elemBuf != nil {
buf = elemBuf
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
}
return buf, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *DateArray) Scan(src interface{}) error {
if src == nil {
return dst.DecodeText(nil, nil)
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src DateArray) Value() (driver.Value, error) {
buf, err := src.EncodeText(nil, nil)
if err != nil {
return nil, err
}
if buf == nil {
return nil, nil
}
return string(buf), nil
}
-267
View File
@@ -1,267 +0,0 @@
package pgtype
import (
"database/sql/driver"
"fmt"
"github.com/jackc/pgio"
)
type Daterange struct {
Lower Date
Upper Date
LowerType BoundType
UpperType BoundType
Status Status
}
func (dst *Daterange) Set(src interface{}) error {
// untyped nil and typed nil interfaces are different
if src == nil {
*dst = Daterange{Status: Null}
return nil
}
switch value := src.(type) {
case Daterange:
*dst = value
case *Daterange:
*dst = *value
case string:
return dst.DecodeText(nil, []byte(value))
default:
return fmt.Errorf("cannot convert %v to Daterange", src)
}
return nil
}
func (dst Daterange) Get() interface{} {
switch dst.Status {
case Present:
return dst
case Null:
return nil
default:
return dst.Status
}
}
func (src *Daterange) AssignTo(dst interface{}) error {
return fmt.Errorf("cannot assign %v to %T", src, dst)
}
func (dst *Daterange) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Daterange{Status: Null}
return nil
}
utr, err := ParseUntypedTextRange(string(src))
if err != nil {
return err
}
*dst = Daterange{Status: Present}
dst.LowerType = utr.LowerType
dst.UpperType = utr.UpperType
if dst.LowerType == Empty {
return nil
}
if dst.LowerType == Inclusive || dst.LowerType == Exclusive {
if err := dst.Lower.DecodeText(ci, []byte(utr.Lower)); err != nil {
return err
}
}
if dst.UpperType == Inclusive || dst.UpperType == Exclusive {
if err := dst.Upper.DecodeText(ci, []byte(utr.Upper)); err != nil {
return err
}
}
return nil
}
func (dst *Daterange) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Daterange{Status: Null}
return nil
}
ubr, err := ParseUntypedBinaryRange(src)
if err != nil {
return err
}
*dst = Daterange{Status: Present}
dst.LowerType = ubr.LowerType
dst.UpperType = ubr.UpperType
if dst.LowerType == Empty {
return nil
}
if dst.LowerType == Inclusive || dst.LowerType == Exclusive {
if err := dst.Lower.DecodeBinary(ci, ubr.Lower); err != nil {
return err
}
}
if dst.UpperType == Inclusive || dst.UpperType == Exclusive {
if err := dst.Upper.DecodeBinary(ci, ubr.Upper); err != nil {
return err
}
}
return nil
}
func (src Daterange) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
switch src.LowerType {
case Exclusive, Unbounded:
buf = append(buf, '(')
case Inclusive:
buf = append(buf, '[')
case Empty:
return append(buf, "empty"...), nil
default:
return nil, fmt.Errorf("unknown lower bound type %v", src.LowerType)
}
var err error
if src.LowerType != Unbounded {
buf, err = src.Lower.EncodeText(ci, buf)
if err != nil {
return nil, err
} else if buf == nil {
return nil, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
}
}
buf = append(buf, ',')
if src.UpperType != Unbounded {
buf, err = src.Upper.EncodeText(ci, buf)
if err != nil {
return nil, err
} else if buf == nil {
return nil, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
}
}
switch src.UpperType {
case Exclusive, Unbounded:
buf = append(buf, ')')
case Inclusive:
buf = append(buf, ']')
default:
return nil, fmt.Errorf("unknown upper bound type %v", src.UpperType)
}
return buf, nil
}
func (src Daterange) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
var rangeType byte
switch src.LowerType {
case Inclusive:
rangeType |= lowerInclusiveMask
case Unbounded:
rangeType |= lowerUnboundedMask
case Exclusive:
case Empty:
return append(buf, emptyMask), nil
default:
return nil, fmt.Errorf("unknown LowerType: %v", src.LowerType)
}
switch src.UpperType {
case Inclusive:
rangeType |= upperInclusiveMask
case Unbounded:
rangeType |= upperUnboundedMask
case Exclusive:
default:
return nil, fmt.Errorf("unknown UpperType: %v", src.UpperType)
}
buf = append(buf, rangeType)
var err error
if src.LowerType != Unbounded {
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
buf, err = src.Lower.EncodeBinary(ci, buf)
if err != nil {
return nil, err
}
if buf == nil {
return nil, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
}
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
if src.UpperType != Unbounded {
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
buf, err = src.Upper.EncodeBinary(ci, buf)
if err != nil {
return nil, err
}
if buf == nil {
return nil, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
}
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
return buf, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *Daterange) Scan(src interface{}) error {
if src == nil {
*dst = Daterange{Status: Null}
return nil
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src Daterange) Value() (driver.Value, error) {
return EncodeValueText(src)
}
-428
View File
@@ -1,428 +0,0 @@
// Code generated by erb. DO NOT EDIT.
package pgtype
import (
"database/sql/driver"
"fmt"
"reflect"
)
type EnumArray struct {
Elements []GenericText
Dimensions []ArrayDimension
Status Status
}
func (dst *EnumArray) Set(src interface{}) error {
// untyped nil and typed nil interfaces are different
if src == nil {
*dst = EnumArray{Status: Null}
return nil
}
if value, ok := src.(interface{ Get() interface{} }); ok {
value2 := value.Get()
if value2 != value {
return dst.Set(value2)
}
}
// Attempt to match to select common types:
switch value := src.(type) {
case []string:
if value == nil {
*dst = EnumArray{Status: Null}
} else if len(value) == 0 {
*dst = EnumArray{Status: Present}
} else {
elements := make([]GenericText, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = EnumArray{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []*string:
if value == nil {
*dst = EnumArray{Status: Null}
} else if len(value) == 0 {
*dst = EnumArray{Status: Present}
} else {
elements := make([]GenericText, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = EnumArray{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []GenericText:
if value == nil {
*dst = EnumArray{Status: Null}
} else if len(value) == 0 {
*dst = EnumArray{Status: Present}
} else {
*dst = EnumArray{
Elements: value,
Dimensions: []ArrayDimension{{Length: int32(len(value)), LowerBound: 1}},
Status: Present,
}
}
default:
// Fallback to reflection if an optimised match was not found.
// The reflection is necessary for arrays and multidimensional slices,
// but it comes with a 20-50% performance penalty for large arrays/slices
reflectedValue := reflect.ValueOf(src)
if !reflectedValue.IsValid() || reflectedValue.IsZero() {
*dst = EnumArray{Status: Null}
return nil
}
dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
if !ok {
return fmt.Errorf("cannot find dimensions of %v for EnumArray", src)
}
if elementsLength == 0 {
*dst = EnumArray{Status: Present}
return nil
}
if len(dimensions) == 0 {
if originalSrc, ok := underlyingSliceType(src); ok {
return dst.Set(originalSrc)
}
return fmt.Errorf("cannot convert %v to EnumArray", src)
}
*dst = EnumArray{
Elements: make([]GenericText, elementsLength),
Dimensions: dimensions,
Status: Present,
}
elementCount, err := dst.setRecursive(reflectedValue, 0, 0)
if err != nil {
// Maybe the target was one dimension too far, try again:
if len(dst.Dimensions) > 1 {
dst.Dimensions = dst.Dimensions[:len(dst.Dimensions)-1]
elementsLength = 0
for _, dim := range dst.Dimensions {
if elementsLength == 0 {
elementsLength = int(dim.Length)
} else {
elementsLength *= int(dim.Length)
}
}
dst.Elements = make([]GenericText, elementsLength)
elementCount, err = dst.setRecursive(reflectedValue, 0, 0)
if err != nil {
return err
}
} else {
return err
}
}
if elementCount != len(dst.Elements) {
return fmt.Errorf("cannot convert %v to EnumArray, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
}
}
return nil
}
func (dst *EnumArray) setRecursive(value reflect.Value, index, dimension int) (int, error) {
switch value.Kind() {
case reflect.Array:
fallthrough
case reflect.Slice:
if len(dst.Dimensions) == dimension {
break
}
valueLen := value.Len()
if int32(valueLen) != dst.Dimensions[dimension].Length {
return 0, fmt.Errorf("multidimensional arrays must have array expressions with matching dimensions")
}
for i := 0; i < valueLen; i++ {
var err error
index, err = dst.setRecursive(value.Index(i), index, dimension+1)
if err != nil {
return 0, err
}
}
return index, nil
}
if !value.CanInterface() {
return 0, fmt.Errorf("cannot convert all values to EnumArray")
}
if err := dst.Elements[index].Set(value.Interface()); err != nil {
return 0, fmt.Errorf("%v in EnumArray", err)
}
index++
return index, nil
}
func (dst EnumArray) Get() interface{} {
switch dst.Status {
case Present:
return dst
case Null:
return nil
default:
return dst.Status
}
}
func (src *EnumArray) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
if len(src.Dimensions) <= 1 {
// Attempt to match to select common types:
switch v := dst.(type) {
case *[]string:
*v = make([]string, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]*string:
*v = make([]*string, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
}
}
// Try to convert to something AssignTo can use directly.
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
// Fallback to reflection if an optimised match was not found.
// The reflection is necessary for arrays and multidimensional slices,
// but it comes with a 20-50% performance penalty for large arrays/slices
value := reflect.ValueOf(dst)
if value.Kind() == reflect.Ptr {
value = value.Elem()
}
switch value.Kind() {
case reflect.Array, reflect.Slice:
default:
return fmt.Errorf("cannot assign %T to %T", src, dst)
}
if len(src.Elements) == 0 {
if value.Kind() == reflect.Slice {
value.Set(reflect.MakeSlice(value.Type(), 0, 0))
return nil
}
}
elementCount, err := src.assignToRecursive(value, 0, 0)
if err != nil {
return err
}
if elementCount != len(src.Elements) {
return fmt.Errorf("cannot assign %v, needed to assign %d elements, but only assigned %d", dst, len(src.Elements), elementCount)
}
return nil
case Null:
return NullAssignTo(dst)
}
return fmt.Errorf("cannot decode %#v into %T", src, dst)
}
func (src *EnumArray) assignToRecursive(value reflect.Value, index, dimension int) (int, error) {
switch kind := value.Kind(); kind {
case reflect.Array:
fallthrough
case reflect.Slice:
if len(src.Dimensions) == dimension {
break
}
length := int(src.Dimensions[dimension].Length)
if reflect.Array == kind {
typ := value.Type()
if typ.Len() != length {
return 0, fmt.Errorf("expected size %d array, but %s has size %d array", length, typ, typ.Len())
}
value.Set(reflect.New(typ).Elem())
} else {
value.Set(reflect.MakeSlice(value.Type(), length, length))
}
var err error
for i := 0; i < length; i++ {
index, err = src.assignToRecursive(value.Index(i), index, dimension+1)
if err != nil {
return 0, err
}
}
return index, nil
}
if len(src.Dimensions) != dimension {
return 0, fmt.Errorf("incorrect dimensions, expected %d, found %d", len(src.Dimensions), dimension)
}
if !value.CanAddr() {
return 0, fmt.Errorf("cannot assign all values from EnumArray")
}
addr := value.Addr()
if !addr.CanInterface() {
return 0, fmt.Errorf("cannot assign all values from EnumArray")
}
if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
return 0, err
}
index++
return index, nil
}
func (dst *EnumArray) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = EnumArray{Status: Null}
return nil
}
uta, err := ParseUntypedTextArray(string(src))
if err != nil {
return err
}
var elements []GenericText
if len(uta.Elements) > 0 {
elements = make([]GenericText, len(uta.Elements))
for i, s := range uta.Elements {
var elem GenericText
var elemSrc []byte
if s != "NULL" || uta.Quoted[i] {
elemSrc = []byte(s)
}
err = elem.DecodeText(ci, elemSrc)
if err != nil {
return err
}
elements[i] = elem
}
}
*dst = EnumArray{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
return nil
}
func (src EnumArray) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
if len(src.Dimensions) == 0 {
return append(buf, '{', '}'), nil
}
buf = EncodeTextArrayDimensions(buf, src.Dimensions)
// dimElemCounts is the multiples of elements that each array lies on. For
// example, a single dimension array of length 4 would have a dimElemCounts of
// [4]. A multi-dimensional array of lengths [3,5,2] would have a
// dimElemCounts of [30,10,2]. This is used to simplify when to render a '{'
// or '}'.
dimElemCounts := make([]int, len(src.Dimensions))
dimElemCounts[len(src.Dimensions)-1] = int(src.Dimensions[len(src.Dimensions)-1].Length)
for i := len(src.Dimensions) - 2; i > -1; i-- {
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
}
inElemBuf := make([]byte, 0, 32)
for i, elem := range src.Elements {
if i > 0 {
buf = append(buf, ',')
}
for _, dec := range dimElemCounts {
if i%dec == 0 {
buf = append(buf, '{')
}
}
elemBuf, err := elem.EncodeText(ci, inElemBuf)
if err != nil {
return nil, err
}
if elemBuf == nil {
buf = append(buf, `NULL`...)
} else {
buf = append(buf, QuoteArrayElementIfNeeded(string(elemBuf))...)
}
for _, dec := range dimElemCounts {
if (i+1)%dec == 0 {
buf = append(buf, '}')
}
}
}
return buf, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *EnumArray) Scan(src interface{}) error {
if src == nil {
return dst.DecodeText(nil, nil)
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src EnumArray) Value() (driver.Value, error) {
buf, err := src.EncodeText(nil, nil)
if err != nil {
return nil, err
}
if buf == nil {
return nil, nil
}
return string(buf), nil
}
-168
View File
@@ -1,168 +0,0 @@
package pgtype
import "fmt"
// EnumType represents an enum type. While it implements Value, this is only in service of its type conversion duties
// when registered as a data type in a ConnType. It should not be used directly as a Value.
type EnumType struct {
value string
status Status
typeName string // PostgreSQL type name
members []string // enum members
membersMap map[string]string // map to quickly lookup member and reuse string instead of allocating
}
// NewEnumType initializes a new EnumType. It retains a read-only reference to members. members must not be changed.
func NewEnumType(typeName string, members []string) *EnumType {
et := &EnumType{typeName: typeName, members: members}
et.membersMap = make(map[string]string, len(members))
for _, m := range members {
et.membersMap[m] = m
}
return et
}
func (et *EnumType) NewTypeValue() Value {
return &EnumType{
value: et.value,
status: et.status,
typeName: et.typeName,
members: et.members,
membersMap: et.membersMap,
}
}
func (et *EnumType) TypeName() string {
return et.typeName
}
func (et *EnumType) Members() []string {
return et.members
}
// Set assigns src to dst. Set purposely does not check that src is a member. This allows continued error free
// operation in the event the PostgreSQL enum type is modified during a connection.
func (dst *EnumType) Set(src interface{}) error {
if src == nil {
dst.status = Null
return nil
}
if value, ok := src.(interface{ Get() interface{} }); ok {
value2 := value.Get()
if value2 != value {
return dst.Set(value2)
}
}
switch value := src.(type) {
case string:
dst.value = value
dst.status = Present
case *string:
if value == nil {
dst.status = Null
} else {
dst.value = *value
dst.status = Present
}
case []byte:
if value == nil {
dst.status = Null
} else {
dst.value = string(value)
dst.status = Present
}
default:
if originalSrc, ok := underlyingStringType(src); ok {
return dst.Set(originalSrc)
}
return fmt.Errorf("cannot convert %v to enum %s", value, dst.typeName)
}
return nil
}
func (dst EnumType) Get() interface{} {
switch dst.status {
case Present:
return dst.value
case Null:
return nil
default:
return dst.status
}
}
func (src *EnumType) AssignTo(dst interface{}) error {
switch src.status {
case Present:
switch v := dst.(type) {
case *string:
*v = src.value
return nil
case *[]byte:
*v = make([]byte, len(src.value))
copy(*v, src.value)
return nil
default:
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
return fmt.Errorf("unable to assign to %T", dst)
}
case Null:
return NullAssignTo(dst)
}
return fmt.Errorf("cannot decode %#v into %T", src, dst)
}
func (EnumType) PreferredResultFormat() int16 {
return TextFormatCode
}
func (dst *EnumType) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
dst.status = Null
return nil
}
// Lookup the string in membersMap to avoid an allocation.
if s, found := dst.membersMap[string(src)]; found {
dst.value = s
} else {
// If an enum type is modified after the initial connection it is possible to receive an unexpected value.
// Gracefully handle this situation. Purposely NOT modifying members and membersMap to allow for sharing members
// and membersMap between connections.
dst.value = string(src)
}
dst.status = Present
return nil
}
func (dst *EnumType) DecodeBinary(ci *ConnInfo, src []byte) error {
return dst.DecodeText(ci, src)
}
func (EnumType) PreferredParamFormat() int16 {
return TextFormatCode
}
func (src EnumType) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
return append(buf, src.value...), nil
}
func (src EnumType) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
return src.EncodeText(ci, buf)
}
-282
View File
@@ -1,282 +0,0 @@
package pgtype
import (
"database/sql/driver"
"encoding/binary"
"fmt"
"math"
"strconv"
"github.com/jackc/pgio"
)
type Float4 struct {
Float float32
Status Status
}
func (dst *Float4) Set(src interface{}) error {
if src == nil {
*dst = Float4{Status: Null}
return nil
}
if value, ok := src.(interface{ Get() interface{} }); ok {
value2 := value.Get()
if value2 != value {
return dst.Set(value2)
}
}
switch value := src.(type) {
case float32:
*dst = Float4{Float: value, Status: Present}
case float64:
*dst = Float4{Float: float32(value), Status: Present}
case int8:
*dst = Float4{Float: float32(value), Status: Present}
case uint8:
*dst = Float4{Float: float32(value), Status: Present}
case int16:
*dst = Float4{Float: float32(value), Status: Present}
case uint16:
*dst = Float4{Float: float32(value), Status: Present}
case int32:
f32 := float32(value)
if int32(f32) == value {
*dst = Float4{Float: f32, Status: Present}
} else {
return fmt.Errorf("%v cannot be exactly represented as float32", value)
}
case uint32:
f32 := float32(value)
if uint32(f32) == value {
*dst = Float4{Float: f32, Status: Present}
} else {
return fmt.Errorf("%v cannot be exactly represented as float32", value)
}
case int64:
f32 := float32(value)
if int64(f32) == value {
*dst = Float4{Float: f32, Status: Present}
} else {
return fmt.Errorf("%v cannot be exactly represented as float32", value)
}
case uint64:
f32 := float32(value)
if uint64(f32) == value {
*dst = Float4{Float: f32, Status: Present}
} else {
return fmt.Errorf("%v cannot be exactly represented as float32", value)
}
case int:
f32 := float32(value)
if int(f32) == value {
*dst = Float4{Float: f32, Status: Present}
} else {
return fmt.Errorf("%v cannot be exactly represented as float32", value)
}
case uint:
f32 := float32(value)
if uint(f32) == value {
*dst = Float4{Float: f32, Status: Present}
} else {
return fmt.Errorf("%v cannot be exactly represented as float32", value)
}
case string:
num, err := strconv.ParseFloat(value, 32)
if err != nil {
return err
}
*dst = Float4{Float: float32(num), Status: Present}
case *float64:
if value == nil {
*dst = Float4{Status: Null}
} else {
return dst.Set(*value)
}
case *float32:
if value == nil {
*dst = Float4{Status: Null}
} else {
return dst.Set(*value)
}
case *int8:
if value == nil {
*dst = Float4{Status: Null}
} else {
return dst.Set(*value)
}
case *uint8:
if value == nil {
*dst = Float4{Status: Null}
} else {
return dst.Set(*value)
}
case *int16:
if value == nil {
*dst = Float4{Status: Null}
} else {
return dst.Set(*value)
}
case *uint16:
if value == nil {
*dst = Float4{Status: Null}
} else {
return dst.Set(*value)
}
case *int32:
if value == nil {
*dst = Float4{Status: Null}
} else {
return dst.Set(*value)
}
case *uint32:
if value == nil {
*dst = Float4{Status: Null}
} else {
return dst.Set(*value)
}
case *int64:
if value == nil {
*dst = Float4{Status: Null}
} else {
return dst.Set(*value)
}
case *uint64:
if value == nil {
*dst = Float4{Status: Null}
} else {
return dst.Set(*value)
}
case *int:
if value == nil {
*dst = Float4{Status: Null}
} else {
return dst.Set(*value)
}
case *uint:
if value == nil {
*dst = Float4{Status: Null}
} else {
return dst.Set(*value)
}
case *string:
if value == nil {
*dst = Float4{Status: Null}
} else {
return dst.Set(*value)
}
default:
if originalSrc, ok := underlyingNumberType(src); ok {
return dst.Set(originalSrc)
}
return fmt.Errorf("cannot convert %v to Float8", value)
}
return nil
}
func (dst Float4) Get() interface{} {
switch dst.Status {
case Present:
return dst.Float
case Null:
return nil
default:
return dst.Status
}
}
func (src *Float4) AssignTo(dst interface{}) error {
return float64AssignTo(float64(src.Float), src.Status, dst)
}
func (dst *Float4) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Float4{Status: Null}
return nil
}
n, err := strconv.ParseFloat(string(src), 32)
if err != nil {
return err
}
*dst = Float4{Float: float32(n), Status: Present}
return nil
}
func (dst *Float4) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Float4{Status: Null}
return nil
}
if len(src) != 4 {
return fmt.Errorf("invalid length for float4: %v", len(src))
}
n := int32(binary.BigEndian.Uint32(src))
*dst = Float4{Float: math.Float32frombits(uint32(n)), Status: Present}
return nil
}
func (src Float4) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
buf = append(buf, strconv.FormatFloat(float64(src.Float), 'f', -1, 32)...)
return buf, nil
}
func (src Float4) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
buf = pgio.AppendUint32(buf, math.Float32bits(src.Float))
return buf, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *Float4) Scan(src interface{}) error {
if src == nil {
*dst = Float4{Status: Null}
return nil
}
switch src := src.(type) {
case float64:
*dst = Float4{Float: float32(src), Status: Present}
return nil
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src Float4) Value() (driver.Value, error) {
switch src.Status {
case Present:
return float64(src.Float), nil
case Null:
return nil, nil
default:
return nil, errUndefined
}
}
-517
View File
@@ -1,517 +0,0 @@
// Code generated by erb. DO NOT EDIT.
package pgtype
import (
"database/sql/driver"
"encoding/binary"
"fmt"
"reflect"
"github.com/jackc/pgio"
)
type Float4Array struct {
Elements []Float4
Dimensions []ArrayDimension
Status Status
}
func (dst *Float4Array) Set(src interface{}) error {
// untyped nil and typed nil interfaces are different
if src == nil {
*dst = Float4Array{Status: Null}
return nil
}
if value, ok := src.(interface{ Get() interface{} }); ok {
value2 := value.Get()
if value2 != value {
return dst.Set(value2)
}
}
// Attempt to match to select common types:
switch value := src.(type) {
case []float32:
if value == nil {
*dst = Float4Array{Status: Null}
} else if len(value) == 0 {
*dst = Float4Array{Status: Present}
} else {
elements := make([]Float4, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Float4Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []*float32:
if value == nil {
*dst = Float4Array{Status: Null}
} else if len(value) == 0 {
*dst = Float4Array{Status: Present}
} else {
elements := make([]Float4, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Float4Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []Float4:
if value == nil {
*dst = Float4Array{Status: Null}
} else if len(value) == 0 {
*dst = Float4Array{Status: Present}
} else {
*dst = Float4Array{
Elements: value,
Dimensions: []ArrayDimension{{Length: int32(len(value)), LowerBound: 1}},
Status: Present,
}
}
default:
// Fallback to reflection if an optimised match was not found.
// The reflection is necessary for arrays and multidimensional slices,
// but it comes with a 20-50% performance penalty for large arrays/slices
reflectedValue := reflect.ValueOf(src)
if !reflectedValue.IsValid() || reflectedValue.IsZero() {
*dst = Float4Array{Status: Null}
return nil
}
dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
if !ok {
return fmt.Errorf("cannot find dimensions of %v for Float4Array", src)
}
if elementsLength == 0 {
*dst = Float4Array{Status: Present}
return nil
}
if len(dimensions) == 0 {
if originalSrc, ok := underlyingSliceType(src); ok {
return dst.Set(originalSrc)
}
return fmt.Errorf("cannot convert %v to Float4Array", src)
}
*dst = Float4Array{
Elements: make([]Float4, elementsLength),
Dimensions: dimensions,
Status: Present,
}
elementCount, err := dst.setRecursive(reflectedValue, 0, 0)
if err != nil {
// Maybe the target was one dimension too far, try again:
if len(dst.Dimensions) > 1 {
dst.Dimensions = dst.Dimensions[:len(dst.Dimensions)-1]
elementsLength = 0
for _, dim := range dst.Dimensions {
if elementsLength == 0 {
elementsLength = int(dim.Length)
} else {
elementsLength *= int(dim.Length)
}
}
dst.Elements = make([]Float4, elementsLength)
elementCount, err = dst.setRecursive(reflectedValue, 0, 0)
if err != nil {
return err
}
} else {
return err
}
}
if elementCount != len(dst.Elements) {
return fmt.Errorf("cannot convert %v to Float4Array, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
}
}
return nil
}
func (dst *Float4Array) setRecursive(value reflect.Value, index, dimension int) (int, error) {
switch value.Kind() {
case reflect.Array:
fallthrough
case reflect.Slice:
if len(dst.Dimensions) == dimension {
break
}
valueLen := value.Len()
if int32(valueLen) != dst.Dimensions[dimension].Length {
return 0, fmt.Errorf("multidimensional arrays must have array expressions with matching dimensions")
}
for i := 0; i < valueLen; i++ {
var err error
index, err = dst.setRecursive(value.Index(i), index, dimension+1)
if err != nil {
return 0, err
}
}
return index, nil
}
if !value.CanInterface() {
return 0, fmt.Errorf("cannot convert all values to Float4Array")
}
if err := dst.Elements[index].Set(value.Interface()); err != nil {
return 0, fmt.Errorf("%v in Float4Array", err)
}
index++
return index, nil
}
func (dst Float4Array) Get() interface{} {
switch dst.Status {
case Present:
return dst
case Null:
return nil
default:
return dst.Status
}
}
func (src *Float4Array) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
if len(src.Dimensions) <= 1 {
// Attempt to match to select common types:
switch v := dst.(type) {
case *[]float32:
*v = make([]float32, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]*float32:
*v = make([]*float32, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
}
}
// Try to convert to something AssignTo can use directly.
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
// Fallback to reflection if an optimised match was not found.
// The reflection is necessary for arrays and multidimensional slices,
// but it comes with a 20-50% performance penalty for large arrays/slices
value := reflect.ValueOf(dst)
if value.Kind() == reflect.Ptr {
value = value.Elem()
}
switch value.Kind() {
case reflect.Array, reflect.Slice:
default:
return fmt.Errorf("cannot assign %T to %T", src, dst)
}
if len(src.Elements) == 0 {
if value.Kind() == reflect.Slice {
value.Set(reflect.MakeSlice(value.Type(), 0, 0))
return nil
}
}
elementCount, err := src.assignToRecursive(value, 0, 0)
if err != nil {
return err
}
if elementCount != len(src.Elements) {
return fmt.Errorf("cannot assign %v, needed to assign %d elements, but only assigned %d", dst, len(src.Elements), elementCount)
}
return nil
case Null:
return NullAssignTo(dst)
}
return fmt.Errorf("cannot decode %#v into %T", src, dst)
}
func (src *Float4Array) assignToRecursive(value reflect.Value, index, dimension int) (int, error) {
switch kind := value.Kind(); kind {
case reflect.Array:
fallthrough
case reflect.Slice:
if len(src.Dimensions) == dimension {
break
}
length := int(src.Dimensions[dimension].Length)
if reflect.Array == kind {
typ := value.Type()
if typ.Len() != length {
return 0, fmt.Errorf("expected size %d array, but %s has size %d array", length, typ, typ.Len())
}
value.Set(reflect.New(typ).Elem())
} else {
value.Set(reflect.MakeSlice(value.Type(), length, length))
}
var err error
for i := 0; i < length; i++ {
index, err = src.assignToRecursive(value.Index(i), index, dimension+1)
if err != nil {
return 0, err
}
}
return index, nil
}
if len(src.Dimensions) != dimension {
return 0, fmt.Errorf("incorrect dimensions, expected %d, found %d", len(src.Dimensions), dimension)
}
if !value.CanAddr() {
return 0, fmt.Errorf("cannot assign all values from Float4Array")
}
addr := value.Addr()
if !addr.CanInterface() {
return 0, fmt.Errorf("cannot assign all values from Float4Array")
}
if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
return 0, err
}
index++
return index, nil
}
func (dst *Float4Array) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Float4Array{Status: Null}
return nil
}
uta, err := ParseUntypedTextArray(string(src))
if err != nil {
return err
}
var elements []Float4
if len(uta.Elements) > 0 {
elements = make([]Float4, len(uta.Elements))
for i, s := range uta.Elements {
var elem Float4
var elemSrc []byte
if s != "NULL" || uta.Quoted[i] {
elemSrc = []byte(s)
}
err = elem.DecodeText(ci, elemSrc)
if err != nil {
return err
}
elements[i] = elem
}
}
*dst = Float4Array{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
return nil
}
func (dst *Float4Array) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Float4Array{Status: Null}
return nil
}
var arrayHeader ArrayHeader
rp, err := arrayHeader.DecodeBinary(ci, src)
if err != nil {
return err
}
if len(arrayHeader.Dimensions) == 0 {
*dst = Float4Array{Dimensions: arrayHeader.Dimensions, Status: Present}
return nil
}
elementCount := arrayHeader.Dimensions[0].Length
for _, d := range arrayHeader.Dimensions[1:] {
elementCount *= d.Length
}
elements := make([]Float4, elementCount)
for i := range elements {
elemLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
rp += 4
var elemSrc []byte
if elemLen >= 0 {
elemSrc = src[rp : rp+elemLen]
rp += elemLen
}
err = elements[i].DecodeBinary(ci, elemSrc)
if err != nil {
return err
}
}
*dst = Float4Array{Elements: elements, Dimensions: arrayHeader.Dimensions, Status: Present}
return nil
}
func (src Float4Array) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
if len(src.Dimensions) == 0 {
return append(buf, '{', '}'), nil
}
buf = EncodeTextArrayDimensions(buf, src.Dimensions)
// dimElemCounts is the multiples of elements that each array lies on. For
// example, a single dimension array of length 4 would have a dimElemCounts of
// [4]. A multi-dimensional array of lengths [3,5,2] would have a
// dimElemCounts of [30,10,2]. This is used to simplify when to render a '{'
// or '}'.
dimElemCounts := make([]int, len(src.Dimensions))
dimElemCounts[len(src.Dimensions)-1] = int(src.Dimensions[len(src.Dimensions)-1].Length)
for i := len(src.Dimensions) - 2; i > -1; i-- {
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
}
inElemBuf := make([]byte, 0, 32)
for i, elem := range src.Elements {
if i > 0 {
buf = append(buf, ',')
}
for _, dec := range dimElemCounts {
if i%dec == 0 {
buf = append(buf, '{')
}
}
elemBuf, err := elem.EncodeText(ci, inElemBuf)
if err != nil {
return nil, err
}
if elemBuf == nil {
buf = append(buf, `NULL`...)
} else {
buf = append(buf, QuoteArrayElementIfNeeded(string(elemBuf))...)
}
for _, dec := range dimElemCounts {
if (i+1)%dec == 0 {
buf = append(buf, '}')
}
}
}
return buf, nil
}
func (src Float4Array) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
arrayHeader := ArrayHeader{
Dimensions: src.Dimensions,
}
if dt, ok := ci.DataTypeForName("float4"); ok {
arrayHeader.ElementOID = int32(dt.OID)
} else {
return nil, fmt.Errorf("unable to find oid for type name %v", "float4")
}
for i := range src.Elements {
if src.Elements[i].Status == Null {
arrayHeader.ContainsNull = true
break
}
}
buf = arrayHeader.EncodeBinary(ci, buf)
for i := range src.Elements {
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
elemBuf, err := src.Elements[i].EncodeBinary(ci, buf)
if err != nil {
return nil, err
}
if elemBuf != nil {
buf = elemBuf
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
}
return buf, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *Float4Array) Scan(src interface{}) error {
if src == nil {
return dst.DecodeText(nil, nil)
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src Float4Array) Value() (driver.Value, error) {
buf, err := src.EncodeText(nil, nil)
if err != nil {
return nil, err
}
if buf == nil {
return nil, nil
}
return string(buf), nil
}
-272
View File
@@ -1,272 +0,0 @@
package pgtype
import (
"database/sql/driver"
"encoding/binary"
"fmt"
"math"
"strconv"
"github.com/jackc/pgio"
)
type Float8 struct {
Float float64
Status Status
}
func (dst *Float8) Set(src interface{}) error {
if src == nil {
*dst = Float8{Status: Null}
return nil
}
if value, ok := src.(interface{ Get() interface{} }); ok {
value2 := value.Get()
if value2 != value {
return dst.Set(value2)
}
}
switch value := src.(type) {
case float32:
*dst = Float8{Float: float64(value), Status: Present}
case float64:
*dst = Float8{Float: value, Status: Present}
case int8:
*dst = Float8{Float: float64(value), Status: Present}
case uint8:
*dst = Float8{Float: float64(value), Status: Present}
case int16:
*dst = Float8{Float: float64(value), Status: Present}
case uint16:
*dst = Float8{Float: float64(value), Status: Present}
case int32:
*dst = Float8{Float: float64(value), Status: Present}
case uint32:
*dst = Float8{Float: float64(value), Status: Present}
case int64:
f64 := float64(value)
if int64(f64) == value {
*dst = Float8{Float: f64, Status: Present}
} else {
return fmt.Errorf("%v cannot be exactly represented as float64", value)
}
case uint64:
f64 := float64(value)
if uint64(f64) == value {
*dst = Float8{Float: f64, Status: Present}
} else {
return fmt.Errorf("%v cannot be exactly represented as float64", value)
}
case int:
f64 := float64(value)
if int(f64) == value {
*dst = Float8{Float: f64, Status: Present}
} else {
return fmt.Errorf("%v cannot be exactly represented as float64", value)
}
case uint:
f64 := float64(value)
if uint(f64) == value {
*dst = Float8{Float: f64, Status: Present}
} else {
return fmt.Errorf("%v cannot be exactly represented as float64", value)
}
case string:
num, err := strconv.ParseFloat(value, 64)
if err != nil {
return err
}
*dst = Float8{Float: float64(num), Status: Present}
case *float64:
if value == nil {
*dst = Float8{Status: Null}
} else {
return dst.Set(*value)
}
case *float32:
if value == nil {
*dst = Float8{Status: Null}
} else {
return dst.Set(*value)
}
case *int8:
if value == nil {
*dst = Float8{Status: Null}
} else {
return dst.Set(*value)
}
case *uint8:
if value == nil {
*dst = Float8{Status: Null}
} else {
return dst.Set(*value)
}
case *int16:
if value == nil {
*dst = Float8{Status: Null}
} else {
return dst.Set(*value)
}
case *uint16:
if value == nil {
*dst = Float8{Status: Null}
} else {
return dst.Set(*value)
}
case *int32:
if value == nil {
*dst = Float8{Status: Null}
} else {
return dst.Set(*value)
}
case *uint32:
if value == nil {
*dst = Float8{Status: Null}
} else {
return dst.Set(*value)
}
case *int64:
if value == nil {
*dst = Float8{Status: Null}
} else {
return dst.Set(*value)
}
case *uint64:
if value == nil {
*dst = Float8{Status: Null}
} else {
return dst.Set(*value)
}
case *int:
if value == nil {
*dst = Float8{Status: Null}
} else {
return dst.Set(*value)
}
case *uint:
if value == nil {
*dst = Float8{Status: Null}
} else {
return dst.Set(*value)
}
case *string:
if value == nil {
*dst = Float8{Status: Null}
} else {
return dst.Set(*value)
}
default:
if originalSrc, ok := underlyingNumberType(src); ok {
return dst.Set(originalSrc)
}
return fmt.Errorf("cannot convert %v to Float8", value)
}
return nil
}
func (dst Float8) Get() interface{} {
switch dst.Status {
case Present:
return dst.Float
case Null:
return nil
default:
return dst.Status
}
}
func (src *Float8) AssignTo(dst interface{}) error {
return float64AssignTo(src.Float, src.Status, dst)
}
func (dst *Float8) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Float8{Status: Null}
return nil
}
n, err := strconv.ParseFloat(string(src), 64)
if err != nil {
return err
}
*dst = Float8{Float: n, Status: Present}
return nil
}
func (dst *Float8) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Float8{Status: Null}
return nil
}
if len(src) != 8 {
return fmt.Errorf("invalid length for float8: %v", len(src))
}
n := int64(binary.BigEndian.Uint64(src))
*dst = Float8{Float: math.Float64frombits(uint64(n)), Status: Present}
return nil
}
func (src Float8) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
buf = append(buf, strconv.FormatFloat(float64(src.Float), 'f', -1, 64)...)
return buf, nil
}
func (src Float8) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
buf = pgio.AppendUint64(buf, math.Float64bits(src.Float))
return buf, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *Float8) Scan(src interface{}) error {
if src == nil {
*dst = Float8{Status: Null}
return nil
}
switch src := src.(type) {
case float64:
*dst = Float8{Float: src, Status: Present}
return nil
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src Float8) Value() (driver.Value, error) {
switch src.Status {
case Present:
return src.Float, nil
case Null:
return nil, nil
default:
return nil, errUndefined
}
}
-517
View File
@@ -1,517 +0,0 @@
// Code generated by erb. DO NOT EDIT.
package pgtype
import (
"database/sql/driver"
"encoding/binary"
"fmt"
"reflect"
"github.com/jackc/pgio"
)
type Float8Array struct {
Elements []Float8
Dimensions []ArrayDimension
Status Status
}
func (dst *Float8Array) Set(src interface{}) error {
// untyped nil and typed nil interfaces are different
if src == nil {
*dst = Float8Array{Status: Null}
return nil
}
if value, ok := src.(interface{ Get() interface{} }); ok {
value2 := value.Get()
if value2 != value {
return dst.Set(value2)
}
}
// Attempt to match to select common types:
switch value := src.(type) {
case []float64:
if value == nil {
*dst = Float8Array{Status: Null}
} else if len(value) == 0 {
*dst = Float8Array{Status: Present}
} else {
elements := make([]Float8, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Float8Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []*float64:
if value == nil {
*dst = Float8Array{Status: Null}
} else if len(value) == 0 {
*dst = Float8Array{Status: Present}
} else {
elements := make([]Float8, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Float8Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []Float8:
if value == nil {
*dst = Float8Array{Status: Null}
} else if len(value) == 0 {
*dst = Float8Array{Status: Present}
} else {
*dst = Float8Array{
Elements: value,
Dimensions: []ArrayDimension{{Length: int32(len(value)), LowerBound: 1}},
Status: Present,
}
}
default:
// Fallback to reflection if an optimised match was not found.
// The reflection is necessary for arrays and multidimensional slices,
// but it comes with a 20-50% performance penalty for large arrays/slices
reflectedValue := reflect.ValueOf(src)
if !reflectedValue.IsValid() || reflectedValue.IsZero() {
*dst = Float8Array{Status: Null}
return nil
}
dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
if !ok {
return fmt.Errorf("cannot find dimensions of %v for Float8Array", src)
}
if elementsLength == 0 {
*dst = Float8Array{Status: Present}
return nil
}
if len(dimensions) == 0 {
if originalSrc, ok := underlyingSliceType(src); ok {
return dst.Set(originalSrc)
}
return fmt.Errorf("cannot convert %v to Float8Array", src)
}
*dst = Float8Array{
Elements: make([]Float8, elementsLength),
Dimensions: dimensions,
Status: Present,
}
elementCount, err := dst.setRecursive(reflectedValue, 0, 0)
if err != nil {
// Maybe the target was one dimension too far, try again:
if len(dst.Dimensions) > 1 {
dst.Dimensions = dst.Dimensions[:len(dst.Dimensions)-1]
elementsLength = 0
for _, dim := range dst.Dimensions {
if elementsLength == 0 {
elementsLength = int(dim.Length)
} else {
elementsLength *= int(dim.Length)
}
}
dst.Elements = make([]Float8, elementsLength)
elementCount, err = dst.setRecursive(reflectedValue, 0, 0)
if err != nil {
return err
}
} else {
return err
}
}
if elementCount != len(dst.Elements) {
return fmt.Errorf("cannot convert %v to Float8Array, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
}
}
return nil
}
func (dst *Float8Array) setRecursive(value reflect.Value, index, dimension int) (int, error) {
switch value.Kind() {
case reflect.Array:
fallthrough
case reflect.Slice:
if len(dst.Dimensions) == dimension {
break
}
valueLen := value.Len()
if int32(valueLen) != dst.Dimensions[dimension].Length {
return 0, fmt.Errorf("multidimensional arrays must have array expressions with matching dimensions")
}
for i := 0; i < valueLen; i++ {
var err error
index, err = dst.setRecursive(value.Index(i), index, dimension+1)
if err != nil {
return 0, err
}
}
return index, nil
}
if !value.CanInterface() {
return 0, fmt.Errorf("cannot convert all values to Float8Array")
}
if err := dst.Elements[index].Set(value.Interface()); err != nil {
return 0, fmt.Errorf("%v in Float8Array", err)
}
index++
return index, nil
}
func (dst Float8Array) Get() interface{} {
switch dst.Status {
case Present:
return dst
case Null:
return nil
default:
return dst.Status
}
}
func (src *Float8Array) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
if len(src.Dimensions) <= 1 {
// Attempt to match to select common types:
switch v := dst.(type) {
case *[]float64:
*v = make([]float64, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]*float64:
*v = make([]*float64, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
}
}
// Try to convert to something AssignTo can use directly.
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
// Fallback to reflection if an optimised match was not found.
// The reflection is necessary for arrays and multidimensional slices,
// but it comes with a 20-50% performance penalty for large arrays/slices
value := reflect.ValueOf(dst)
if value.Kind() == reflect.Ptr {
value = value.Elem()
}
switch value.Kind() {
case reflect.Array, reflect.Slice:
default:
return fmt.Errorf("cannot assign %T to %T", src, dst)
}
if len(src.Elements) == 0 {
if value.Kind() == reflect.Slice {
value.Set(reflect.MakeSlice(value.Type(), 0, 0))
return nil
}
}
elementCount, err := src.assignToRecursive(value, 0, 0)
if err != nil {
return err
}
if elementCount != len(src.Elements) {
return fmt.Errorf("cannot assign %v, needed to assign %d elements, but only assigned %d", dst, len(src.Elements), elementCount)
}
return nil
case Null:
return NullAssignTo(dst)
}
return fmt.Errorf("cannot decode %#v into %T", src, dst)
}
func (src *Float8Array) assignToRecursive(value reflect.Value, index, dimension int) (int, error) {
switch kind := value.Kind(); kind {
case reflect.Array:
fallthrough
case reflect.Slice:
if len(src.Dimensions) == dimension {
break
}
length := int(src.Dimensions[dimension].Length)
if reflect.Array == kind {
typ := value.Type()
if typ.Len() != length {
return 0, fmt.Errorf("expected size %d array, but %s has size %d array", length, typ, typ.Len())
}
value.Set(reflect.New(typ).Elem())
} else {
value.Set(reflect.MakeSlice(value.Type(), length, length))
}
var err error
for i := 0; i < length; i++ {
index, err = src.assignToRecursive(value.Index(i), index, dimension+1)
if err != nil {
return 0, err
}
}
return index, nil
}
if len(src.Dimensions) != dimension {
return 0, fmt.Errorf("incorrect dimensions, expected %d, found %d", len(src.Dimensions), dimension)
}
if !value.CanAddr() {
return 0, fmt.Errorf("cannot assign all values from Float8Array")
}
addr := value.Addr()
if !addr.CanInterface() {
return 0, fmt.Errorf("cannot assign all values from Float8Array")
}
if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
return 0, err
}
index++
return index, nil
}
func (dst *Float8Array) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Float8Array{Status: Null}
return nil
}
uta, err := ParseUntypedTextArray(string(src))
if err != nil {
return err
}
var elements []Float8
if len(uta.Elements) > 0 {
elements = make([]Float8, len(uta.Elements))
for i, s := range uta.Elements {
var elem Float8
var elemSrc []byte
if s != "NULL" || uta.Quoted[i] {
elemSrc = []byte(s)
}
err = elem.DecodeText(ci, elemSrc)
if err != nil {
return err
}
elements[i] = elem
}
}
*dst = Float8Array{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
return nil
}
func (dst *Float8Array) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Float8Array{Status: Null}
return nil
}
var arrayHeader ArrayHeader
rp, err := arrayHeader.DecodeBinary(ci, src)
if err != nil {
return err
}
if len(arrayHeader.Dimensions) == 0 {
*dst = Float8Array{Dimensions: arrayHeader.Dimensions, Status: Present}
return nil
}
elementCount := arrayHeader.Dimensions[0].Length
for _, d := range arrayHeader.Dimensions[1:] {
elementCount *= d.Length
}
elements := make([]Float8, elementCount)
for i := range elements {
elemLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
rp += 4
var elemSrc []byte
if elemLen >= 0 {
elemSrc = src[rp : rp+elemLen]
rp += elemLen
}
err = elements[i].DecodeBinary(ci, elemSrc)
if err != nil {
return err
}
}
*dst = Float8Array{Elements: elements, Dimensions: arrayHeader.Dimensions, Status: Present}
return nil
}
func (src Float8Array) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
if len(src.Dimensions) == 0 {
return append(buf, '{', '}'), nil
}
buf = EncodeTextArrayDimensions(buf, src.Dimensions)
// dimElemCounts is the multiples of elements that each array lies on. For
// example, a single dimension array of length 4 would have a dimElemCounts of
// [4]. A multi-dimensional array of lengths [3,5,2] would have a
// dimElemCounts of [30,10,2]. This is used to simplify when to render a '{'
// or '}'.
dimElemCounts := make([]int, len(src.Dimensions))
dimElemCounts[len(src.Dimensions)-1] = int(src.Dimensions[len(src.Dimensions)-1].Length)
for i := len(src.Dimensions) - 2; i > -1; i-- {
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
}
inElemBuf := make([]byte, 0, 32)
for i, elem := range src.Elements {
if i > 0 {
buf = append(buf, ',')
}
for _, dec := range dimElemCounts {
if i%dec == 0 {
buf = append(buf, '{')
}
}
elemBuf, err := elem.EncodeText(ci, inElemBuf)
if err != nil {
return nil, err
}
if elemBuf == nil {
buf = append(buf, `NULL`...)
} else {
buf = append(buf, QuoteArrayElementIfNeeded(string(elemBuf))...)
}
for _, dec := range dimElemCounts {
if (i+1)%dec == 0 {
buf = append(buf, '}')
}
}
}
return buf, nil
}
func (src Float8Array) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
arrayHeader := ArrayHeader{
Dimensions: src.Dimensions,
}
if dt, ok := ci.DataTypeForName("float8"); ok {
arrayHeader.ElementOID = int32(dt.OID)
} else {
return nil, fmt.Errorf("unable to find oid for type name %v", "float8")
}
for i := range src.Elements {
if src.Elements[i].Status == Null {
arrayHeader.ContainsNull = true
break
}
}
buf = arrayHeader.EncodeBinary(ci, buf)
for i := range src.Elements {
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
elemBuf, err := src.Elements[i].EncodeBinary(ci, buf)
if err != nil {
return nil, err
}
if elemBuf != nil {
buf = elemBuf
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
}
return buf, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *Float8Array) Scan(src interface{}) error {
if src == nil {
return dst.DecodeText(nil, nil)
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src Float8Array) Value() (driver.Value, error) {
buf, err := src.EncodeText(nil, nil)
if err != nil {
return nil, err
}
if buf == nil {
return nil, nil
}
return string(buf), nil
}
-39
View File
@@ -1,39 +0,0 @@
package pgtype
import (
"database/sql/driver"
)
// GenericBinary is a placeholder for binary format values that no other type exists
// to handle.
type GenericBinary Bytea
func (dst *GenericBinary) Set(src interface{}) error {
return (*Bytea)(dst).Set(src)
}
func (dst GenericBinary) Get() interface{} {
return (Bytea)(dst).Get()
}
func (src *GenericBinary) AssignTo(dst interface{}) error {
return (*Bytea)(src).AssignTo(dst)
}
func (dst *GenericBinary) DecodeBinary(ci *ConnInfo, src []byte) error {
return (*Bytea)(dst).DecodeBinary(ci, src)
}
func (src GenericBinary) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
return (Bytea)(src).EncodeBinary(ci, buf)
}
// Scan implements the database/sql Scanner interface.
func (dst *GenericBinary) Scan(src interface{}) error {
return (*Bytea)(dst).Scan(src)
}
// Value implements the database/sql/driver Valuer interface.
func (src GenericBinary) Value() (driver.Value, error) {
return (Bytea)(src).Value()
}
-39
View File
@@ -1,39 +0,0 @@
package pgtype
import (
"database/sql/driver"
)
// GenericText is a placeholder for text format values that no other type exists
// to handle.
type GenericText Text
func (dst *GenericText) Set(src interface{}) error {
return (*Text)(dst).Set(src)
}
func (dst GenericText) Get() interface{} {
return (Text)(dst).Get()
}
func (src *GenericText) AssignTo(dst interface{}) error {
return (*Text)(src).AssignTo(dst)
}
func (dst *GenericText) DecodeText(ci *ConnInfo, src []byte) error {
return (*Text)(dst).DecodeText(ci, src)
}
func (src GenericText) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
return (Text)(src).EncodeText(ci, buf)
}
// Scan implements the database/sql Scanner interface.
func (dst *GenericText) Scan(src interface{}) error {
return (*Text)(dst).Scan(src)
}
// Value implements the database/sql/driver Valuer interface.
func (src GenericText) Value() (driver.Value, error) {
return (Text)(src).Value()
}
-489
View File
@@ -1,489 +0,0 @@
// Code generated by erb. DO NOT EDIT.
package pgtype
import (
"database/sql/driver"
"encoding/binary"
"fmt"
"reflect"
"github.com/jackc/pgio"
)
type HstoreArray struct {
Elements []Hstore
Dimensions []ArrayDimension
Status Status
}
func (dst *HstoreArray) Set(src interface{}) error {
// untyped nil and typed nil interfaces are different
if src == nil {
*dst = HstoreArray{Status: Null}
return nil
}
if value, ok := src.(interface{ Get() interface{} }); ok {
value2 := value.Get()
if value2 != value {
return dst.Set(value2)
}
}
// Attempt to match to select common types:
switch value := src.(type) {
case []map[string]string:
if value == nil {
*dst = HstoreArray{Status: Null}
} else if len(value) == 0 {
*dst = HstoreArray{Status: Present}
} else {
elements := make([]Hstore, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = HstoreArray{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []Hstore:
if value == nil {
*dst = HstoreArray{Status: Null}
} else if len(value) == 0 {
*dst = HstoreArray{Status: Present}
} else {
*dst = HstoreArray{
Elements: value,
Dimensions: []ArrayDimension{{Length: int32(len(value)), LowerBound: 1}},
Status: Present,
}
}
default:
// Fallback to reflection if an optimised match was not found.
// The reflection is necessary for arrays and multidimensional slices,
// but it comes with a 20-50% performance penalty for large arrays/slices
reflectedValue := reflect.ValueOf(src)
if !reflectedValue.IsValid() || reflectedValue.IsZero() {
*dst = HstoreArray{Status: Null}
return nil
}
dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
if !ok {
return fmt.Errorf("cannot find dimensions of %v for HstoreArray", src)
}
if elementsLength == 0 {
*dst = HstoreArray{Status: Present}
return nil
}
if len(dimensions) == 0 {
if originalSrc, ok := underlyingSliceType(src); ok {
return dst.Set(originalSrc)
}
return fmt.Errorf("cannot convert %v to HstoreArray", src)
}
*dst = HstoreArray{
Elements: make([]Hstore, elementsLength),
Dimensions: dimensions,
Status: Present,
}
elementCount, err := dst.setRecursive(reflectedValue, 0, 0)
if err != nil {
// Maybe the target was one dimension too far, try again:
if len(dst.Dimensions) > 1 {
dst.Dimensions = dst.Dimensions[:len(dst.Dimensions)-1]
elementsLength = 0
for _, dim := range dst.Dimensions {
if elementsLength == 0 {
elementsLength = int(dim.Length)
} else {
elementsLength *= int(dim.Length)
}
}
dst.Elements = make([]Hstore, elementsLength)
elementCount, err = dst.setRecursive(reflectedValue, 0, 0)
if err != nil {
return err
}
} else {
return err
}
}
if elementCount != len(dst.Elements) {
return fmt.Errorf("cannot convert %v to HstoreArray, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
}
}
return nil
}
func (dst *HstoreArray) setRecursive(value reflect.Value, index, dimension int) (int, error) {
switch value.Kind() {
case reflect.Array:
fallthrough
case reflect.Slice:
if len(dst.Dimensions) == dimension {
break
}
valueLen := value.Len()
if int32(valueLen) != dst.Dimensions[dimension].Length {
return 0, fmt.Errorf("multidimensional arrays must have array expressions with matching dimensions")
}
for i := 0; i < valueLen; i++ {
var err error
index, err = dst.setRecursive(value.Index(i), index, dimension+1)
if err != nil {
return 0, err
}
}
return index, nil
}
if !value.CanInterface() {
return 0, fmt.Errorf("cannot convert all values to HstoreArray")
}
if err := dst.Elements[index].Set(value.Interface()); err != nil {
return 0, fmt.Errorf("%v in HstoreArray", err)
}
index++
return index, nil
}
func (dst HstoreArray) Get() interface{} {
switch dst.Status {
case Present:
return dst
case Null:
return nil
default:
return dst.Status
}
}
func (src *HstoreArray) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
if len(src.Dimensions) <= 1 {
// Attempt to match to select common types:
switch v := dst.(type) {
case *[]map[string]string:
*v = make([]map[string]string, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
}
}
// Try to convert to something AssignTo can use directly.
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
// Fallback to reflection if an optimised match was not found.
// The reflection is necessary for arrays and multidimensional slices,
// but it comes with a 20-50% performance penalty for large arrays/slices
value := reflect.ValueOf(dst)
if value.Kind() == reflect.Ptr {
value = value.Elem()
}
switch value.Kind() {
case reflect.Array, reflect.Slice:
default:
return fmt.Errorf("cannot assign %T to %T", src, dst)
}
if len(src.Elements) == 0 {
if value.Kind() == reflect.Slice {
value.Set(reflect.MakeSlice(value.Type(), 0, 0))
return nil
}
}
elementCount, err := src.assignToRecursive(value, 0, 0)
if err != nil {
return err
}
if elementCount != len(src.Elements) {
return fmt.Errorf("cannot assign %v, needed to assign %d elements, but only assigned %d", dst, len(src.Elements), elementCount)
}
return nil
case Null:
return NullAssignTo(dst)
}
return fmt.Errorf("cannot decode %#v into %T", src, dst)
}
func (src *HstoreArray) assignToRecursive(value reflect.Value, index, dimension int) (int, error) {
switch kind := value.Kind(); kind {
case reflect.Array:
fallthrough
case reflect.Slice:
if len(src.Dimensions) == dimension {
break
}
length := int(src.Dimensions[dimension].Length)
if reflect.Array == kind {
typ := value.Type()
if typ.Len() != length {
return 0, fmt.Errorf("expected size %d array, but %s has size %d array", length, typ, typ.Len())
}
value.Set(reflect.New(typ).Elem())
} else {
value.Set(reflect.MakeSlice(value.Type(), length, length))
}
var err error
for i := 0; i < length; i++ {
index, err = src.assignToRecursive(value.Index(i), index, dimension+1)
if err != nil {
return 0, err
}
}
return index, nil
}
if len(src.Dimensions) != dimension {
return 0, fmt.Errorf("incorrect dimensions, expected %d, found %d", len(src.Dimensions), dimension)
}
if !value.CanAddr() {
return 0, fmt.Errorf("cannot assign all values from HstoreArray")
}
addr := value.Addr()
if !addr.CanInterface() {
return 0, fmt.Errorf("cannot assign all values from HstoreArray")
}
if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
return 0, err
}
index++
return index, nil
}
func (dst *HstoreArray) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = HstoreArray{Status: Null}
return nil
}
uta, err := ParseUntypedTextArray(string(src))
if err != nil {
return err
}
var elements []Hstore
if len(uta.Elements) > 0 {
elements = make([]Hstore, len(uta.Elements))
for i, s := range uta.Elements {
var elem Hstore
var elemSrc []byte
if s != "NULL" || uta.Quoted[i] {
elemSrc = []byte(s)
}
err = elem.DecodeText(ci, elemSrc)
if err != nil {
return err
}
elements[i] = elem
}
}
*dst = HstoreArray{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
return nil
}
func (dst *HstoreArray) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = HstoreArray{Status: Null}
return nil
}
var arrayHeader ArrayHeader
rp, err := arrayHeader.DecodeBinary(ci, src)
if err != nil {
return err
}
if len(arrayHeader.Dimensions) == 0 {
*dst = HstoreArray{Dimensions: arrayHeader.Dimensions, Status: Present}
return nil
}
elementCount := arrayHeader.Dimensions[0].Length
for _, d := range arrayHeader.Dimensions[1:] {
elementCount *= d.Length
}
elements := make([]Hstore, elementCount)
for i := range elements {
elemLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
rp += 4
var elemSrc []byte
if elemLen >= 0 {
elemSrc = src[rp : rp+elemLen]
rp += elemLen
}
err = elements[i].DecodeBinary(ci, elemSrc)
if err != nil {
return err
}
}
*dst = HstoreArray{Elements: elements, Dimensions: arrayHeader.Dimensions, Status: Present}
return nil
}
func (src HstoreArray) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
if len(src.Dimensions) == 0 {
return append(buf, '{', '}'), nil
}
buf = EncodeTextArrayDimensions(buf, src.Dimensions)
// dimElemCounts is the multiples of elements that each array lies on. For
// example, a single dimension array of length 4 would have a dimElemCounts of
// [4]. A multi-dimensional array of lengths [3,5,2] would have a
// dimElemCounts of [30,10,2]. This is used to simplify when to render a '{'
// or '}'.
dimElemCounts := make([]int, len(src.Dimensions))
dimElemCounts[len(src.Dimensions)-1] = int(src.Dimensions[len(src.Dimensions)-1].Length)
for i := len(src.Dimensions) - 2; i > -1; i-- {
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
}
inElemBuf := make([]byte, 0, 32)
for i, elem := range src.Elements {
if i > 0 {
buf = append(buf, ',')
}
for _, dec := range dimElemCounts {
if i%dec == 0 {
buf = append(buf, '{')
}
}
elemBuf, err := elem.EncodeText(ci, inElemBuf)
if err != nil {
return nil, err
}
if elemBuf == nil {
buf = append(buf, `NULL`...)
} else {
buf = append(buf, QuoteArrayElementIfNeeded(string(elemBuf))...)
}
for _, dec := range dimElemCounts {
if (i+1)%dec == 0 {
buf = append(buf, '}')
}
}
}
return buf, nil
}
func (src HstoreArray) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
arrayHeader := ArrayHeader{
Dimensions: src.Dimensions,
}
if dt, ok := ci.DataTypeForName("hstore"); ok {
arrayHeader.ElementOID = int32(dt.OID)
} else {
return nil, fmt.Errorf("unable to find oid for type name %v", "hstore")
}
for i := range src.Elements {
if src.Elements[i].Status == Null {
arrayHeader.ContainsNull = true
break
}
}
buf = arrayHeader.EncodeBinary(ci, buf)
for i := range src.Elements {
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
elemBuf, err := src.Elements[i].EncodeBinary(ci, buf)
if err != nil {
return nil, err
}
if elemBuf != nil {
buf = elemBuf
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
}
return buf, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *HstoreArray) Scan(src interface{}) error {
if src == nil {
return dst.DecodeText(nil, nil)
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src HstoreArray) Value() (driver.Value, error) {
buf, err := src.EncodeText(nil, nil)
if err != nil {
return nil, err
}
if buf == nil {
return nil, nil
}
return string(buf), nil
}
-304
View File
@@ -1,304 +0,0 @@
package pgtype
import (
"database/sql/driver"
"encoding"
"fmt"
"net"
"strings"
)
// Network address family is dependent on server socket.h value for AF_INET.
// In practice, all platforms appear to have the same value. See
// src/include/utils/inet.h for more information.
const (
defaultAFInet = 2
defaultAFInet6 = 3
)
// Inet represents both inet and cidr PostgreSQL types.
type Inet struct {
IPNet *net.IPNet
Status Status
}
func (dst *Inet) Set(src interface{}) error {
if src == nil {
*dst = Inet{Status: Null}
return nil
}
if value, ok := src.(interface{ Get() interface{} }); ok {
value2 := value.Get()
if value2 != value {
return dst.Set(value2)
}
}
switch value := src.(type) {
case net.IPNet:
*dst = Inet{IPNet: &value, Status: Present}
case net.IP:
if len(value) == 0 {
*dst = Inet{Status: Null}
} else {
bitCount := len(value) * 8
mask := net.CIDRMask(bitCount, bitCount)
*dst = Inet{IPNet: &net.IPNet{Mask: mask, IP: value}, Status: Present}
}
case string:
ip, ipnet, err := net.ParseCIDR(value)
if err != nil {
ip := net.ParseIP(value)
if ip == nil {
return fmt.Errorf("unable to parse inet address: %s", value)
}
if ipv4 := maybeGetIPv4(value, ip); ipv4 != nil {
ipnet = &net.IPNet{IP: ipv4, Mask: net.CIDRMask(32, 32)}
} else {
ipnet = &net.IPNet{IP: ip, Mask: net.CIDRMask(128, 128)}
}
} else {
ipnet.IP = ip
if ipv4 := maybeGetIPv4(value, ipnet.IP); ipv4 != nil {
ipnet.IP = ipv4
if len(ipnet.Mask) == 16 {
ipnet.Mask = ipnet.Mask[12:] // Not sure this is ever needed.
}
}
}
*dst = Inet{IPNet: ipnet, Status: Present}
case *net.IPNet:
if value == nil {
*dst = Inet{Status: Null}
} else {
return dst.Set(*value)
}
case *net.IP:
if value == nil {
*dst = Inet{Status: Null}
} else {
return dst.Set(*value)
}
case *string:
if value == nil {
*dst = Inet{Status: Null}
} else {
return dst.Set(*value)
}
default:
if tv, ok := src.(encoding.TextMarshaler); ok {
text, err := tv.MarshalText()
if err != nil {
return fmt.Errorf("cannot marshal %v: %w", value, err)
}
return dst.Set(string(text))
}
if sv, ok := src.(fmt.Stringer); ok {
return dst.Set(sv.String())
}
if originalSrc, ok := underlyingPtrType(src); ok {
return dst.Set(originalSrc)
}
return fmt.Errorf("cannot convert %v to Inet", value)
}
return nil
}
// Convert the net.IP to IPv4, if appropriate.
//
// When parsing a string to a net.IP using net.ParseIP() and the like, we get a
// 16 byte slice for IPv4 addresses as well as IPv6 addresses. This function
// calls To4() to convert them to a 4 byte slice. This is useful as it allows
// users of the net.IP check for IPv4 addresses based on the length and makes
// it clear we are handling IPv4 as opposed to IPv6 or IPv4-mapped IPv6
// addresses.
func maybeGetIPv4(input string, ip net.IP) net.IP {
// Do not do this if the provided input looks like IPv6. This is because
// To4() on IPv4-mapped IPv6 addresses converts them to IPv4, which behave
// different in some cases.
if strings.Contains(input, ":") {
return nil
}
return ip.To4()
}
func (dst Inet) Get() interface{} {
switch dst.Status {
case Present:
return dst.IPNet
case Null:
return nil
default:
return dst.Status
}
}
func (src *Inet) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
switch v := dst.(type) {
case *net.IPNet:
*v = net.IPNet{
IP: make(net.IP, len(src.IPNet.IP)),
Mask: make(net.IPMask, len(src.IPNet.Mask)),
}
copy(v.IP, src.IPNet.IP)
copy(v.Mask, src.IPNet.Mask)
return nil
case *net.IP:
if oneCount, bitCount := src.IPNet.Mask.Size(); oneCount != bitCount {
return fmt.Errorf("cannot assign %v to %T", src, dst)
}
*v = make(net.IP, len(src.IPNet.IP))
copy(*v, src.IPNet.IP)
return nil
default:
if tv, ok := dst.(encoding.TextUnmarshaler); ok {
if err := tv.UnmarshalText([]byte(src.IPNet.String())); err != nil {
return fmt.Errorf("cannot unmarshal %v to %T: %w", src, dst, err)
}
return nil
}
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
return fmt.Errorf("unable to assign to %T", dst)
}
case Null:
return NullAssignTo(dst)
}
return fmt.Errorf("cannot decode %#v into %T", src, dst)
}
func (dst *Inet) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Inet{Status: Null}
return nil
}
var ipnet *net.IPNet
var err error
if ip := net.ParseIP(string(src)); ip != nil {
if ipv4 := ip.To4(); ipv4 != nil {
ip = ipv4
}
bitCount := len(ip) * 8
mask := net.CIDRMask(bitCount, bitCount)
ipnet = &net.IPNet{Mask: mask, IP: ip}
} else {
ip, ipnet, err = net.ParseCIDR(string(src))
if err != nil {
return err
}
if ipv4 := ip.To4(); ipv4 != nil {
ip = ipv4
}
ones, _ := ipnet.Mask.Size()
*ipnet = net.IPNet{IP: ip, Mask: net.CIDRMask(ones, len(ip)*8)}
}
*dst = Inet{IPNet: ipnet, Status: Present}
return nil
}
func (dst *Inet) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Inet{Status: Null}
return nil
}
if len(src) != 8 && len(src) != 20 {
return fmt.Errorf("Received an invalid size for an inet: %d", len(src))
}
// ignore family
bits := src[1]
// ignore is_cidr
addressLength := src[3]
var ipnet net.IPNet
ipnet.IP = make(net.IP, int(addressLength))
copy(ipnet.IP, src[4:])
if ipv4 := ipnet.IP.To4(); ipv4 != nil {
ipnet.IP = ipv4
}
ipnet.Mask = net.CIDRMask(int(bits), len(ipnet.IP)*8)
*dst = Inet{IPNet: &ipnet, Status: Present}
return nil
}
func (src Inet) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
return append(buf, src.IPNet.String()...), nil
}
// EncodeBinary encodes src into w.
func (src Inet) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
var family byte
switch len(src.IPNet.IP) {
case net.IPv4len:
family = defaultAFInet
case net.IPv6len:
family = defaultAFInet6
default:
return nil, fmt.Errorf("Unexpected IP length: %v", len(src.IPNet.IP))
}
buf = append(buf, family)
ones, _ := src.IPNet.Mask.Size()
buf = append(buf, byte(ones))
// is_cidr is ignored on server
buf = append(buf, 0)
buf = append(buf, byte(len(src.IPNet.IP)))
return append(buf, src.IPNet.IP...), nil
}
// Scan implements the database/sql Scanner interface.
func (dst *Inet) Scan(src interface{}) error {
if src == nil {
*dst = Inet{Status: Null}
return nil
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src Inet) Value() (driver.Value, error) {
return EncodeValueText(src)
}
-546
View File
@@ -1,546 +0,0 @@
// Code generated by erb. DO NOT EDIT.
package pgtype
import (
"database/sql/driver"
"encoding/binary"
"fmt"
"net"
"reflect"
"github.com/jackc/pgio"
)
type InetArray struct {
Elements []Inet
Dimensions []ArrayDimension
Status Status
}
func (dst *InetArray) Set(src interface{}) error {
// untyped nil and typed nil interfaces are different
if src == nil {
*dst = InetArray{Status: Null}
return nil
}
if value, ok := src.(interface{ Get() interface{} }); ok {
value2 := value.Get()
if value2 != value {
return dst.Set(value2)
}
}
// Attempt to match to select common types:
switch value := src.(type) {
case []*net.IPNet:
if value == nil {
*dst = InetArray{Status: Null}
} else if len(value) == 0 {
*dst = InetArray{Status: Present}
} else {
elements := make([]Inet, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = InetArray{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []net.IP:
if value == nil {
*dst = InetArray{Status: Null}
} else if len(value) == 0 {
*dst = InetArray{Status: Present}
} else {
elements := make([]Inet, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = InetArray{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []*net.IP:
if value == nil {
*dst = InetArray{Status: Null}
} else if len(value) == 0 {
*dst = InetArray{Status: Present}
} else {
elements := make([]Inet, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = InetArray{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []Inet:
if value == nil {
*dst = InetArray{Status: Null}
} else if len(value) == 0 {
*dst = InetArray{Status: Present}
} else {
*dst = InetArray{
Elements: value,
Dimensions: []ArrayDimension{{Length: int32(len(value)), LowerBound: 1}},
Status: Present,
}
}
default:
// Fallback to reflection if an optimised match was not found.
// The reflection is necessary for arrays and multidimensional slices,
// but it comes with a 20-50% performance penalty for large arrays/slices
reflectedValue := reflect.ValueOf(src)
if !reflectedValue.IsValid() || reflectedValue.IsZero() {
*dst = InetArray{Status: Null}
return nil
}
dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
if !ok {
return fmt.Errorf("cannot find dimensions of %v for InetArray", src)
}
if elementsLength == 0 {
*dst = InetArray{Status: Present}
return nil
}
if len(dimensions) == 0 {
if originalSrc, ok := underlyingSliceType(src); ok {
return dst.Set(originalSrc)
}
return fmt.Errorf("cannot convert %v to InetArray", src)
}
*dst = InetArray{
Elements: make([]Inet, elementsLength),
Dimensions: dimensions,
Status: Present,
}
elementCount, err := dst.setRecursive(reflectedValue, 0, 0)
if err != nil {
// Maybe the target was one dimension too far, try again:
if len(dst.Dimensions) > 1 {
dst.Dimensions = dst.Dimensions[:len(dst.Dimensions)-1]
elementsLength = 0
for _, dim := range dst.Dimensions {
if elementsLength == 0 {
elementsLength = int(dim.Length)
} else {
elementsLength *= int(dim.Length)
}
}
dst.Elements = make([]Inet, elementsLength)
elementCount, err = dst.setRecursive(reflectedValue, 0, 0)
if err != nil {
return err
}
} else {
return err
}
}
if elementCount != len(dst.Elements) {
return fmt.Errorf("cannot convert %v to InetArray, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
}
}
return nil
}
func (dst *InetArray) setRecursive(value reflect.Value, index, dimension int) (int, error) {
switch value.Kind() {
case reflect.Array:
fallthrough
case reflect.Slice:
if len(dst.Dimensions) == dimension {
break
}
valueLen := value.Len()
if int32(valueLen) != dst.Dimensions[dimension].Length {
return 0, fmt.Errorf("multidimensional arrays must have array expressions with matching dimensions")
}
for i := 0; i < valueLen; i++ {
var err error
index, err = dst.setRecursive(value.Index(i), index, dimension+1)
if err != nil {
return 0, err
}
}
return index, nil
}
if !value.CanInterface() {
return 0, fmt.Errorf("cannot convert all values to InetArray")
}
if err := dst.Elements[index].Set(value.Interface()); err != nil {
return 0, fmt.Errorf("%v in InetArray", err)
}
index++
return index, nil
}
func (dst InetArray) Get() interface{} {
switch dst.Status {
case Present:
return dst
case Null:
return nil
default:
return dst.Status
}
}
func (src *InetArray) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
if len(src.Dimensions) <= 1 {
// Attempt to match to select common types:
switch v := dst.(type) {
case *[]*net.IPNet:
*v = make([]*net.IPNet, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]net.IP:
*v = make([]net.IP, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]*net.IP:
*v = make([]*net.IP, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
}
}
// Try to convert to something AssignTo can use directly.
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
// Fallback to reflection if an optimised match was not found.
// The reflection is necessary for arrays and multidimensional slices,
// but it comes with a 20-50% performance penalty for large arrays/slices
value := reflect.ValueOf(dst)
if value.Kind() == reflect.Ptr {
value = value.Elem()
}
switch value.Kind() {
case reflect.Array, reflect.Slice:
default:
return fmt.Errorf("cannot assign %T to %T", src, dst)
}
if len(src.Elements) == 0 {
if value.Kind() == reflect.Slice {
value.Set(reflect.MakeSlice(value.Type(), 0, 0))
return nil
}
}
elementCount, err := src.assignToRecursive(value, 0, 0)
if err != nil {
return err
}
if elementCount != len(src.Elements) {
return fmt.Errorf("cannot assign %v, needed to assign %d elements, but only assigned %d", dst, len(src.Elements), elementCount)
}
return nil
case Null:
return NullAssignTo(dst)
}
return fmt.Errorf("cannot decode %#v into %T", src, dst)
}
func (src *InetArray) assignToRecursive(value reflect.Value, index, dimension int) (int, error) {
switch kind := value.Kind(); kind {
case reflect.Array:
fallthrough
case reflect.Slice:
if len(src.Dimensions) == dimension {
break
}
length := int(src.Dimensions[dimension].Length)
if reflect.Array == kind {
typ := value.Type()
if typ.Len() != length {
return 0, fmt.Errorf("expected size %d array, but %s has size %d array", length, typ, typ.Len())
}
value.Set(reflect.New(typ).Elem())
} else {
value.Set(reflect.MakeSlice(value.Type(), length, length))
}
var err error
for i := 0; i < length; i++ {
index, err = src.assignToRecursive(value.Index(i), index, dimension+1)
if err != nil {
return 0, err
}
}
return index, nil
}
if len(src.Dimensions) != dimension {
return 0, fmt.Errorf("incorrect dimensions, expected %d, found %d", len(src.Dimensions), dimension)
}
if !value.CanAddr() {
return 0, fmt.Errorf("cannot assign all values from InetArray")
}
addr := value.Addr()
if !addr.CanInterface() {
return 0, fmt.Errorf("cannot assign all values from InetArray")
}
if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
return 0, err
}
index++
return index, nil
}
func (dst *InetArray) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = InetArray{Status: Null}
return nil
}
uta, err := ParseUntypedTextArray(string(src))
if err != nil {
return err
}
var elements []Inet
if len(uta.Elements) > 0 {
elements = make([]Inet, len(uta.Elements))
for i, s := range uta.Elements {
var elem Inet
var elemSrc []byte
if s != "NULL" || uta.Quoted[i] {
elemSrc = []byte(s)
}
err = elem.DecodeText(ci, elemSrc)
if err != nil {
return err
}
elements[i] = elem
}
}
*dst = InetArray{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
return nil
}
func (dst *InetArray) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = InetArray{Status: Null}
return nil
}
var arrayHeader ArrayHeader
rp, err := arrayHeader.DecodeBinary(ci, src)
if err != nil {
return err
}
if len(arrayHeader.Dimensions) == 0 {
*dst = InetArray{Dimensions: arrayHeader.Dimensions, Status: Present}
return nil
}
elementCount := arrayHeader.Dimensions[0].Length
for _, d := range arrayHeader.Dimensions[1:] {
elementCount *= d.Length
}
elements := make([]Inet, elementCount)
for i := range elements {
elemLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
rp += 4
var elemSrc []byte
if elemLen >= 0 {
elemSrc = src[rp : rp+elemLen]
rp += elemLen
}
err = elements[i].DecodeBinary(ci, elemSrc)
if err != nil {
return err
}
}
*dst = InetArray{Elements: elements, Dimensions: arrayHeader.Dimensions, Status: Present}
return nil
}
func (src InetArray) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
if len(src.Dimensions) == 0 {
return append(buf, '{', '}'), nil
}
buf = EncodeTextArrayDimensions(buf, src.Dimensions)
// dimElemCounts is the multiples of elements that each array lies on. For
// example, a single dimension array of length 4 would have a dimElemCounts of
// [4]. A multi-dimensional array of lengths [3,5,2] would have a
// dimElemCounts of [30,10,2]. This is used to simplify when to render a '{'
// or '}'.
dimElemCounts := make([]int, len(src.Dimensions))
dimElemCounts[len(src.Dimensions)-1] = int(src.Dimensions[len(src.Dimensions)-1].Length)
for i := len(src.Dimensions) - 2; i > -1; i-- {
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
}
inElemBuf := make([]byte, 0, 32)
for i, elem := range src.Elements {
if i > 0 {
buf = append(buf, ',')
}
for _, dec := range dimElemCounts {
if i%dec == 0 {
buf = append(buf, '{')
}
}
elemBuf, err := elem.EncodeText(ci, inElemBuf)
if err != nil {
return nil, err
}
if elemBuf == nil {
buf = append(buf, `NULL`...)
} else {
buf = append(buf, QuoteArrayElementIfNeeded(string(elemBuf))...)
}
for _, dec := range dimElemCounts {
if (i+1)%dec == 0 {
buf = append(buf, '}')
}
}
}
return buf, nil
}
func (src InetArray) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
arrayHeader := ArrayHeader{
Dimensions: src.Dimensions,
}
if dt, ok := ci.DataTypeForName("inet"); ok {
arrayHeader.ElementOID = int32(dt.OID)
} else {
return nil, fmt.Errorf("unable to find oid for type name %v", "inet")
}
for i := range src.Elements {
if src.Elements[i].Status == Null {
arrayHeader.ContainsNull = true
break
}
}
buf = arrayHeader.EncodeBinary(ci, buf)
for i := range src.Elements {
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
elemBuf, err := src.Elements[i].EncodeBinary(ci, buf)
if err != nil {
return nil, err
}
if elemBuf != nil {
buf = elemBuf
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
}
return buf, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *InetArray) Scan(src interface{}) error {
if src == nil {
return dst.DecodeText(nil, nil)
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src InetArray) Value() (driver.Value, error) {
buf, err := src.EncodeText(nil, nil)
if err != nil {
return nil, err
}
if buf == nil {
return nil, nil
}
return string(buf), nil
}
-321
View File
@@ -1,321 +0,0 @@
package pgtype
import (
"database/sql/driver"
"encoding/binary"
"encoding/json"
"fmt"
"math"
"strconv"
"github.com/jackc/pgio"
)
type Int2 struct {
Int int16
Status Status
}
func (dst *Int2) Set(src interface{}) error {
if src == nil {
*dst = Int2{Status: Null}
return nil
}
if value, ok := src.(interface{ Get() interface{} }); ok {
value2 := value.Get()
if value2 != value {
return dst.Set(value2)
}
}
switch value := src.(type) {
case int8:
*dst = Int2{Int: int16(value), Status: Present}
case uint8:
*dst = Int2{Int: int16(value), Status: Present}
case int16:
*dst = Int2{Int: int16(value), Status: Present}
case uint16:
if value > math.MaxInt16 {
return fmt.Errorf("%d is greater than maximum value for Int2", value)
}
*dst = Int2{Int: int16(value), Status: Present}
case int32:
if value < math.MinInt16 {
return fmt.Errorf("%d is greater than maximum value for Int2", value)
}
if value > math.MaxInt16 {
return fmt.Errorf("%d is greater than maximum value for Int2", value)
}
*dst = Int2{Int: int16(value), Status: Present}
case uint32:
if value > math.MaxInt16 {
return fmt.Errorf("%d is greater than maximum value for Int2", value)
}
*dst = Int2{Int: int16(value), Status: Present}
case int64:
if value < math.MinInt16 {
return fmt.Errorf("%d is greater than maximum value for Int2", value)
}
if value > math.MaxInt16 {
return fmt.Errorf("%d is greater than maximum value for Int2", value)
}
*dst = Int2{Int: int16(value), Status: Present}
case uint64:
if value > math.MaxInt16 {
return fmt.Errorf("%d is greater than maximum value for Int2", value)
}
*dst = Int2{Int: int16(value), Status: Present}
case int:
if value < math.MinInt16 {
return fmt.Errorf("%d is greater than maximum value for Int2", value)
}
if value > math.MaxInt16 {
return fmt.Errorf("%d is greater than maximum value for Int2", value)
}
*dst = Int2{Int: int16(value), Status: Present}
case uint:
if value > math.MaxInt16 {
return fmt.Errorf("%d is greater than maximum value for Int2", value)
}
*dst = Int2{Int: int16(value), Status: Present}
case string:
num, err := strconv.ParseInt(value, 10, 16)
if err != nil {
return err
}
*dst = Int2{Int: int16(num), Status: Present}
case float32:
if value > math.MaxInt16 {
return fmt.Errorf("%f is greater than maximum value for Int2", value)
}
*dst = Int2{Int: int16(value), Status: Present}
case float64:
if value > math.MaxInt16 {
return fmt.Errorf("%f is greater than maximum value for Int2", value)
}
*dst = Int2{Int: int16(value), Status: Present}
case *int8:
if value == nil {
*dst = Int2{Status: Null}
} else {
return dst.Set(*value)
}
case *uint8:
if value == nil {
*dst = Int2{Status: Null}
} else {
return dst.Set(*value)
}
case *int16:
if value == nil {
*dst = Int2{Status: Null}
} else {
return dst.Set(*value)
}
case *uint16:
if value == nil {
*dst = Int2{Status: Null}
} else {
return dst.Set(*value)
}
case *int32:
if value == nil {
*dst = Int2{Status: Null}
} else {
return dst.Set(*value)
}
case *uint32:
if value == nil {
*dst = Int2{Status: Null}
} else {
return dst.Set(*value)
}
case *int64:
if value == nil {
*dst = Int2{Status: Null}
} else {
return dst.Set(*value)
}
case *uint64:
if value == nil {
*dst = Int2{Status: Null}
} else {
return dst.Set(*value)
}
case *int:
if value == nil {
*dst = Int2{Status: Null}
} else {
return dst.Set(*value)
}
case *uint:
if value == nil {
*dst = Int2{Status: Null}
} else {
return dst.Set(*value)
}
case *string:
if value == nil {
*dst = Int2{Status: Null}
} else {
return dst.Set(*value)
}
case *float32:
if value == nil {
*dst = Int2{Status: Null}
} else {
return dst.Set(*value)
}
case *float64:
if value == nil {
*dst = Int2{Status: Null}
} else {
return dst.Set(*value)
}
default:
if originalSrc, ok := underlyingNumberType(src); ok {
return dst.Set(originalSrc)
}
return fmt.Errorf("cannot convert %v to Int2", value)
}
return nil
}
func (dst Int2) Get() interface{} {
switch dst.Status {
case Present:
return dst.Int
case Null:
return nil
default:
return dst.Status
}
}
func (src *Int2) AssignTo(dst interface{}) error {
return int64AssignTo(int64(src.Int), src.Status, dst)
}
func (dst *Int2) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Int2{Status: Null}
return nil
}
n, err := strconv.ParseInt(string(src), 10, 16)
if err != nil {
return err
}
*dst = Int2{Int: int16(n), Status: Present}
return nil
}
func (dst *Int2) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Int2{Status: Null}
return nil
}
if len(src) != 2 {
return fmt.Errorf("invalid length for int2: %v", len(src))
}
n := int16(binary.BigEndian.Uint16(src))
*dst = Int2{Int: n, Status: Present}
return nil
}
func (src Int2) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
return append(buf, strconv.FormatInt(int64(src.Int), 10)...), nil
}
func (src Int2) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
return pgio.AppendInt16(buf, src.Int), nil
}
// Scan implements the database/sql Scanner interface.
func (dst *Int2) Scan(src interface{}) error {
if src == nil {
*dst = Int2{Status: Null}
return nil
}
switch src := src.(type) {
case int64:
if src < math.MinInt16 {
return fmt.Errorf("%d is greater than maximum value for Int2", src)
}
if src > math.MaxInt16 {
return fmt.Errorf("%d is greater than maximum value for Int2", src)
}
*dst = Int2{Int: int16(src), Status: Present}
return nil
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src Int2) Value() (driver.Value, error) {
switch src.Status {
case Present:
return int64(src.Int), nil
case Null:
return nil, nil
default:
return nil, errUndefined
}
}
func (src Int2) MarshalJSON() ([]byte, error) {
switch src.Status {
case Present:
return []byte(strconv.FormatInt(int64(src.Int), 10)), nil
case Null:
return []byte("null"), nil
case Undefined:
return nil, errUndefined
}
return nil, errBadStatus
}
func (dst *Int2) UnmarshalJSON(b []byte) error {
var n *int16
err := json.Unmarshal(b, &n)
if err != nil {
return err
}
if n == nil {
*dst = Int2{Status: Null}
} else {
*dst = Int2{Int: *n, Status: Present}
}
return nil
}
-909
View File
@@ -1,909 +0,0 @@
// Code generated by erb. DO NOT EDIT.
package pgtype
import (
"database/sql/driver"
"encoding/binary"
"fmt"
"reflect"
"github.com/jackc/pgio"
)
type Int2Array struct {
Elements []Int2
Dimensions []ArrayDimension
Status Status
}
func (dst *Int2Array) Set(src interface{}) error {
// untyped nil and typed nil interfaces are different
if src == nil {
*dst = Int2Array{Status: Null}
return nil
}
if value, ok := src.(interface{ Get() interface{} }); ok {
value2 := value.Get()
if value2 != value {
return dst.Set(value2)
}
}
// Attempt to match to select common types:
switch value := src.(type) {
case []int16:
if value == nil {
*dst = Int2Array{Status: Null}
} else if len(value) == 0 {
*dst = Int2Array{Status: Present}
} else {
elements := make([]Int2, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int2Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []*int16:
if value == nil {
*dst = Int2Array{Status: Null}
} else if len(value) == 0 {
*dst = Int2Array{Status: Present}
} else {
elements := make([]Int2, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int2Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []uint16:
if value == nil {
*dst = Int2Array{Status: Null}
} else if len(value) == 0 {
*dst = Int2Array{Status: Present}
} else {
elements := make([]Int2, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int2Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []*uint16:
if value == nil {
*dst = Int2Array{Status: Null}
} else if len(value) == 0 {
*dst = Int2Array{Status: Present}
} else {
elements := make([]Int2, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int2Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []int32:
if value == nil {
*dst = Int2Array{Status: Null}
} else if len(value) == 0 {
*dst = Int2Array{Status: Present}
} else {
elements := make([]Int2, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int2Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []*int32:
if value == nil {
*dst = Int2Array{Status: Null}
} else if len(value) == 0 {
*dst = Int2Array{Status: Present}
} else {
elements := make([]Int2, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int2Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []uint32:
if value == nil {
*dst = Int2Array{Status: Null}
} else if len(value) == 0 {
*dst = Int2Array{Status: Present}
} else {
elements := make([]Int2, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int2Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []*uint32:
if value == nil {
*dst = Int2Array{Status: Null}
} else if len(value) == 0 {
*dst = Int2Array{Status: Present}
} else {
elements := make([]Int2, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int2Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []int64:
if value == nil {
*dst = Int2Array{Status: Null}
} else if len(value) == 0 {
*dst = Int2Array{Status: Present}
} else {
elements := make([]Int2, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int2Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []*int64:
if value == nil {
*dst = Int2Array{Status: Null}
} else if len(value) == 0 {
*dst = Int2Array{Status: Present}
} else {
elements := make([]Int2, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int2Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []uint64:
if value == nil {
*dst = Int2Array{Status: Null}
} else if len(value) == 0 {
*dst = Int2Array{Status: Present}
} else {
elements := make([]Int2, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int2Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []*uint64:
if value == nil {
*dst = Int2Array{Status: Null}
} else if len(value) == 0 {
*dst = Int2Array{Status: Present}
} else {
elements := make([]Int2, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int2Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []int:
if value == nil {
*dst = Int2Array{Status: Null}
} else if len(value) == 0 {
*dst = Int2Array{Status: Present}
} else {
elements := make([]Int2, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int2Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []*int:
if value == nil {
*dst = Int2Array{Status: Null}
} else if len(value) == 0 {
*dst = Int2Array{Status: Present}
} else {
elements := make([]Int2, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int2Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []uint:
if value == nil {
*dst = Int2Array{Status: Null}
} else if len(value) == 0 {
*dst = Int2Array{Status: Present}
} else {
elements := make([]Int2, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int2Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []*uint:
if value == nil {
*dst = Int2Array{Status: Null}
} else if len(value) == 0 {
*dst = Int2Array{Status: Present}
} else {
elements := make([]Int2, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int2Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []Int2:
if value == nil {
*dst = Int2Array{Status: Null}
} else if len(value) == 0 {
*dst = Int2Array{Status: Present}
} else {
*dst = Int2Array{
Elements: value,
Dimensions: []ArrayDimension{{Length: int32(len(value)), LowerBound: 1}},
Status: Present,
}
}
default:
// Fallback to reflection if an optimised match was not found.
// The reflection is necessary for arrays and multidimensional slices,
// but it comes with a 20-50% performance penalty for large arrays/slices
reflectedValue := reflect.ValueOf(src)
if !reflectedValue.IsValid() || reflectedValue.IsZero() {
*dst = Int2Array{Status: Null}
return nil
}
dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
if !ok {
return fmt.Errorf("cannot find dimensions of %v for Int2Array", src)
}
if elementsLength == 0 {
*dst = Int2Array{Status: Present}
return nil
}
if len(dimensions) == 0 {
if originalSrc, ok := underlyingSliceType(src); ok {
return dst.Set(originalSrc)
}
return fmt.Errorf("cannot convert %v to Int2Array", src)
}
*dst = Int2Array{
Elements: make([]Int2, elementsLength),
Dimensions: dimensions,
Status: Present,
}
elementCount, err := dst.setRecursive(reflectedValue, 0, 0)
if err != nil {
// Maybe the target was one dimension too far, try again:
if len(dst.Dimensions) > 1 {
dst.Dimensions = dst.Dimensions[:len(dst.Dimensions)-1]
elementsLength = 0
for _, dim := range dst.Dimensions {
if elementsLength == 0 {
elementsLength = int(dim.Length)
} else {
elementsLength *= int(dim.Length)
}
}
dst.Elements = make([]Int2, elementsLength)
elementCount, err = dst.setRecursive(reflectedValue, 0, 0)
if err != nil {
return err
}
} else {
return err
}
}
if elementCount != len(dst.Elements) {
return fmt.Errorf("cannot convert %v to Int2Array, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
}
}
return nil
}
func (dst *Int2Array) setRecursive(value reflect.Value, index, dimension int) (int, error) {
switch value.Kind() {
case reflect.Array:
fallthrough
case reflect.Slice:
if len(dst.Dimensions) == dimension {
break
}
valueLen := value.Len()
if int32(valueLen) != dst.Dimensions[dimension].Length {
return 0, fmt.Errorf("multidimensional arrays must have array expressions with matching dimensions")
}
for i := 0; i < valueLen; i++ {
var err error
index, err = dst.setRecursive(value.Index(i), index, dimension+1)
if err != nil {
return 0, err
}
}
return index, nil
}
if !value.CanInterface() {
return 0, fmt.Errorf("cannot convert all values to Int2Array")
}
if err := dst.Elements[index].Set(value.Interface()); err != nil {
return 0, fmt.Errorf("%v in Int2Array", err)
}
index++
return index, nil
}
func (dst Int2Array) Get() interface{} {
switch dst.Status {
case Present:
return dst
case Null:
return nil
default:
return dst.Status
}
}
func (src *Int2Array) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
if len(src.Dimensions) <= 1 {
// Attempt to match to select common types:
switch v := dst.(type) {
case *[]int16:
*v = make([]int16, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]*int16:
*v = make([]*int16, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]uint16:
*v = make([]uint16, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]*uint16:
*v = make([]*uint16, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]int32:
*v = make([]int32, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]*int32:
*v = make([]*int32, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]uint32:
*v = make([]uint32, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]*uint32:
*v = make([]*uint32, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]int64:
*v = make([]int64, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]*int64:
*v = make([]*int64, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]uint64:
*v = make([]uint64, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]*uint64:
*v = make([]*uint64, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]int:
*v = make([]int, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]*int:
*v = make([]*int, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]uint:
*v = make([]uint, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]*uint:
*v = make([]*uint, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
}
}
// Try to convert to something AssignTo can use directly.
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
// Fallback to reflection if an optimised match was not found.
// The reflection is necessary for arrays and multidimensional slices,
// but it comes with a 20-50% performance penalty for large arrays/slices
value := reflect.ValueOf(dst)
if value.Kind() == reflect.Ptr {
value = value.Elem()
}
switch value.Kind() {
case reflect.Array, reflect.Slice:
default:
return fmt.Errorf("cannot assign %T to %T", src, dst)
}
if len(src.Elements) == 0 {
if value.Kind() == reflect.Slice {
value.Set(reflect.MakeSlice(value.Type(), 0, 0))
return nil
}
}
elementCount, err := src.assignToRecursive(value, 0, 0)
if err != nil {
return err
}
if elementCount != len(src.Elements) {
return fmt.Errorf("cannot assign %v, needed to assign %d elements, but only assigned %d", dst, len(src.Elements), elementCount)
}
return nil
case Null:
return NullAssignTo(dst)
}
return fmt.Errorf("cannot decode %#v into %T", src, dst)
}
func (src *Int2Array) assignToRecursive(value reflect.Value, index, dimension int) (int, error) {
switch kind := value.Kind(); kind {
case reflect.Array:
fallthrough
case reflect.Slice:
if len(src.Dimensions) == dimension {
break
}
length := int(src.Dimensions[dimension].Length)
if reflect.Array == kind {
typ := value.Type()
if typ.Len() != length {
return 0, fmt.Errorf("expected size %d array, but %s has size %d array", length, typ, typ.Len())
}
value.Set(reflect.New(typ).Elem())
} else {
value.Set(reflect.MakeSlice(value.Type(), length, length))
}
var err error
for i := 0; i < length; i++ {
index, err = src.assignToRecursive(value.Index(i), index, dimension+1)
if err != nil {
return 0, err
}
}
return index, nil
}
if len(src.Dimensions) != dimension {
return 0, fmt.Errorf("incorrect dimensions, expected %d, found %d", len(src.Dimensions), dimension)
}
if !value.CanAddr() {
return 0, fmt.Errorf("cannot assign all values from Int2Array")
}
addr := value.Addr()
if !addr.CanInterface() {
return 0, fmt.Errorf("cannot assign all values from Int2Array")
}
if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
return 0, err
}
index++
return index, nil
}
func (dst *Int2Array) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Int2Array{Status: Null}
return nil
}
uta, err := ParseUntypedTextArray(string(src))
if err != nil {
return err
}
var elements []Int2
if len(uta.Elements) > 0 {
elements = make([]Int2, len(uta.Elements))
for i, s := range uta.Elements {
var elem Int2
var elemSrc []byte
if s != "NULL" || uta.Quoted[i] {
elemSrc = []byte(s)
}
err = elem.DecodeText(ci, elemSrc)
if err != nil {
return err
}
elements[i] = elem
}
}
*dst = Int2Array{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
return nil
}
func (dst *Int2Array) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Int2Array{Status: Null}
return nil
}
var arrayHeader ArrayHeader
rp, err := arrayHeader.DecodeBinary(ci, src)
if err != nil {
return err
}
if len(arrayHeader.Dimensions) == 0 {
*dst = Int2Array{Dimensions: arrayHeader.Dimensions, Status: Present}
return nil
}
elementCount := arrayHeader.Dimensions[0].Length
for _, d := range arrayHeader.Dimensions[1:] {
elementCount *= d.Length
}
elements := make([]Int2, elementCount)
for i := range elements {
elemLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
rp += 4
var elemSrc []byte
if elemLen >= 0 {
elemSrc = src[rp : rp+elemLen]
rp += elemLen
}
err = elements[i].DecodeBinary(ci, elemSrc)
if err != nil {
return err
}
}
*dst = Int2Array{Elements: elements, Dimensions: arrayHeader.Dimensions, Status: Present}
return nil
}
func (src Int2Array) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
if len(src.Dimensions) == 0 {
return append(buf, '{', '}'), nil
}
buf = EncodeTextArrayDimensions(buf, src.Dimensions)
// dimElemCounts is the multiples of elements that each array lies on. For
// example, a single dimension array of length 4 would have a dimElemCounts of
// [4]. A multi-dimensional array of lengths [3,5,2] would have a
// dimElemCounts of [30,10,2]. This is used to simplify when to render a '{'
// or '}'.
dimElemCounts := make([]int, len(src.Dimensions))
dimElemCounts[len(src.Dimensions)-1] = int(src.Dimensions[len(src.Dimensions)-1].Length)
for i := len(src.Dimensions) - 2; i > -1; i-- {
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
}
inElemBuf := make([]byte, 0, 32)
for i, elem := range src.Elements {
if i > 0 {
buf = append(buf, ',')
}
for _, dec := range dimElemCounts {
if i%dec == 0 {
buf = append(buf, '{')
}
}
elemBuf, err := elem.EncodeText(ci, inElemBuf)
if err != nil {
return nil, err
}
if elemBuf == nil {
buf = append(buf, `NULL`...)
} else {
buf = append(buf, QuoteArrayElementIfNeeded(string(elemBuf))...)
}
for _, dec := range dimElemCounts {
if (i+1)%dec == 0 {
buf = append(buf, '}')
}
}
}
return buf, nil
}
func (src Int2Array) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
arrayHeader := ArrayHeader{
Dimensions: src.Dimensions,
}
if dt, ok := ci.DataTypeForName("int2"); ok {
arrayHeader.ElementOID = int32(dt.OID)
} else {
return nil, fmt.Errorf("unable to find oid for type name %v", "int2")
}
for i := range src.Elements {
if src.Elements[i].Status == Null {
arrayHeader.ContainsNull = true
break
}
}
buf = arrayHeader.EncodeBinary(ci, buf)
for i := range src.Elements {
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
elemBuf, err := src.Elements[i].EncodeBinary(ci, buf)
if err != nil {
return nil, err
}
if elemBuf != nil {
buf = elemBuf
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
}
return buf, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *Int2Array) Scan(src interface{}) error {
if src == nil {
return dst.DecodeText(nil, nil)
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src Int2Array) Value() (driver.Value, error) {
buf, err := src.EncodeText(nil, nil)
if err != nil {
return nil, err
}
if buf == nil {
return nil, nil
}
return string(buf), nil
}
-312
View File
@@ -1,312 +0,0 @@
package pgtype
import (
"database/sql/driver"
"encoding/binary"
"encoding/json"
"fmt"
"math"
"strconv"
"github.com/jackc/pgio"
)
type Int4 struct {
Int int32
Status Status
}
func (dst *Int4) Set(src interface{}) error {
if src == nil {
*dst = Int4{Status: Null}
return nil
}
if value, ok := src.(interface{ Get() interface{} }); ok {
value2 := value.Get()
if value2 != value {
return dst.Set(value2)
}
}
switch value := src.(type) {
case int8:
*dst = Int4{Int: int32(value), Status: Present}
case uint8:
*dst = Int4{Int: int32(value), Status: Present}
case int16:
*dst = Int4{Int: int32(value), Status: Present}
case uint16:
*dst = Int4{Int: int32(value), Status: Present}
case int32:
*dst = Int4{Int: int32(value), Status: Present}
case uint32:
if value > math.MaxInt32 {
return fmt.Errorf("%d is greater than maximum value for Int4", value)
}
*dst = Int4{Int: int32(value), Status: Present}
case int64:
if value < math.MinInt32 {
return fmt.Errorf("%d is greater than maximum value for Int4", value)
}
if value > math.MaxInt32 {
return fmt.Errorf("%d is greater than maximum value for Int4", value)
}
*dst = Int4{Int: int32(value), Status: Present}
case uint64:
if value > math.MaxInt32 {
return fmt.Errorf("%d is greater than maximum value for Int4", value)
}
*dst = Int4{Int: int32(value), Status: Present}
case int:
if value < math.MinInt32 {
return fmt.Errorf("%d is greater than maximum value for Int4", value)
}
if value > math.MaxInt32 {
return fmt.Errorf("%d is greater than maximum value for Int4", value)
}
*dst = Int4{Int: int32(value), Status: Present}
case uint:
if value > math.MaxInt32 {
return fmt.Errorf("%d is greater than maximum value for Int4", value)
}
*dst = Int4{Int: int32(value), Status: Present}
case string:
num, err := strconv.ParseInt(value, 10, 32)
if err != nil {
return err
}
*dst = Int4{Int: int32(num), Status: Present}
case float32:
if value > math.MaxInt32 {
return fmt.Errorf("%f is greater than maximum value for Int4", value)
}
*dst = Int4{Int: int32(value), Status: Present}
case float64:
if value > math.MaxInt32 {
return fmt.Errorf("%f is greater than maximum value for Int4", value)
}
*dst = Int4{Int: int32(value), Status: Present}
case *int8:
if value == nil {
*dst = Int4{Status: Null}
} else {
return dst.Set(*value)
}
case *uint8:
if value == nil {
*dst = Int4{Status: Null}
} else {
return dst.Set(*value)
}
case *int16:
if value == nil {
*dst = Int4{Status: Null}
} else {
return dst.Set(*value)
}
case *uint16:
if value == nil {
*dst = Int4{Status: Null}
} else {
return dst.Set(*value)
}
case *int32:
if value == nil {
*dst = Int4{Status: Null}
} else {
return dst.Set(*value)
}
case *uint32:
if value == nil {
*dst = Int4{Status: Null}
} else {
return dst.Set(*value)
}
case *int64:
if value == nil {
*dst = Int4{Status: Null}
} else {
return dst.Set(*value)
}
case *uint64:
if value == nil {
*dst = Int4{Status: Null}
} else {
return dst.Set(*value)
}
case *int:
if value == nil {
*dst = Int4{Status: Null}
} else {
return dst.Set(*value)
}
case *uint:
if value == nil {
*dst = Int4{Status: Null}
} else {
return dst.Set(*value)
}
case *string:
if value == nil {
*dst = Int4{Status: Null}
} else {
return dst.Set(*value)
}
case *float32:
if value == nil {
*dst = Int4{Status: Null}
} else {
return dst.Set(*value)
}
case *float64:
if value == nil {
*dst = Int4{Status: Null}
} else {
return dst.Set(*value)
}
default:
if originalSrc, ok := underlyingNumberType(src); ok {
return dst.Set(originalSrc)
}
return fmt.Errorf("cannot convert %v to Int4", value)
}
return nil
}
func (dst Int4) Get() interface{} {
switch dst.Status {
case Present:
return dst.Int
case Null:
return nil
default:
return dst.Status
}
}
func (src *Int4) AssignTo(dst interface{}) error {
return int64AssignTo(int64(src.Int), src.Status, dst)
}
func (dst *Int4) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Int4{Status: Null}
return nil
}
n, err := strconv.ParseInt(string(src), 10, 32)
if err != nil {
return err
}
*dst = Int4{Int: int32(n), Status: Present}
return nil
}
func (dst *Int4) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Int4{Status: Null}
return nil
}
if len(src) != 4 {
return fmt.Errorf("invalid length for int4: %v", len(src))
}
n := int32(binary.BigEndian.Uint32(src))
*dst = Int4{Int: n, Status: Present}
return nil
}
func (src Int4) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
return append(buf, strconv.FormatInt(int64(src.Int), 10)...), nil
}
func (src Int4) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
return pgio.AppendInt32(buf, src.Int), nil
}
// Scan implements the database/sql Scanner interface.
func (dst *Int4) Scan(src interface{}) error {
if src == nil {
*dst = Int4{Status: Null}
return nil
}
switch src := src.(type) {
case int64:
if src < math.MinInt32 {
return fmt.Errorf("%d is greater than maximum value for Int4", src)
}
if src > math.MaxInt32 {
return fmt.Errorf("%d is greater than maximum value for Int4", src)
}
*dst = Int4{Int: int32(src), Status: Present}
return nil
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src Int4) Value() (driver.Value, error) {
switch src.Status {
case Present:
return int64(src.Int), nil
case Null:
return nil, nil
default:
return nil, errUndefined
}
}
func (src Int4) MarshalJSON() ([]byte, error) {
switch src.Status {
case Present:
return []byte(strconv.FormatInt(int64(src.Int), 10)), nil
case Null:
return []byte("null"), nil
case Undefined:
return nil, errUndefined
}
return nil, errBadStatus
}
func (dst *Int4) UnmarshalJSON(b []byte) error {
var n *int32
err := json.Unmarshal(b, &n)
if err != nil {
return err
}
if n == nil {
*dst = Int4{Status: Null}
} else {
*dst = Int4{Int: *n, Status: Present}
}
return nil
}
-909
View File
@@ -1,909 +0,0 @@
// Code generated by erb. DO NOT EDIT.
package pgtype
import (
"database/sql/driver"
"encoding/binary"
"fmt"
"reflect"
"github.com/jackc/pgio"
)
type Int4Array struct {
Elements []Int4
Dimensions []ArrayDimension
Status Status
}
func (dst *Int4Array) Set(src interface{}) error {
// untyped nil and typed nil interfaces are different
if src == nil {
*dst = Int4Array{Status: Null}
return nil
}
if value, ok := src.(interface{ Get() interface{} }); ok {
value2 := value.Get()
if value2 != value {
return dst.Set(value2)
}
}
// Attempt to match to select common types:
switch value := src.(type) {
case []int16:
if value == nil {
*dst = Int4Array{Status: Null}
} else if len(value) == 0 {
*dst = Int4Array{Status: Present}
} else {
elements := make([]Int4, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int4Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []*int16:
if value == nil {
*dst = Int4Array{Status: Null}
} else if len(value) == 0 {
*dst = Int4Array{Status: Present}
} else {
elements := make([]Int4, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int4Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []uint16:
if value == nil {
*dst = Int4Array{Status: Null}
} else if len(value) == 0 {
*dst = Int4Array{Status: Present}
} else {
elements := make([]Int4, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int4Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []*uint16:
if value == nil {
*dst = Int4Array{Status: Null}
} else if len(value) == 0 {
*dst = Int4Array{Status: Present}
} else {
elements := make([]Int4, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int4Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []int32:
if value == nil {
*dst = Int4Array{Status: Null}
} else if len(value) == 0 {
*dst = Int4Array{Status: Present}
} else {
elements := make([]Int4, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int4Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []*int32:
if value == nil {
*dst = Int4Array{Status: Null}
} else if len(value) == 0 {
*dst = Int4Array{Status: Present}
} else {
elements := make([]Int4, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int4Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []uint32:
if value == nil {
*dst = Int4Array{Status: Null}
} else if len(value) == 0 {
*dst = Int4Array{Status: Present}
} else {
elements := make([]Int4, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int4Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []*uint32:
if value == nil {
*dst = Int4Array{Status: Null}
} else if len(value) == 0 {
*dst = Int4Array{Status: Present}
} else {
elements := make([]Int4, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int4Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []int64:
if value == nil {
*dst = Int4Array{Status: Null}
} else if len(value) == 0 {
*dst = Int4Array{Status: Present}
} else {
elements := make([]Int4, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int4Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []*int64:
if value == nil {
*dst = Int4Array{Status: Null}
} else if len(value) == 0 {
*dst = Int4Array{Status: Present}
} else {
elements := make([]Int4, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int4Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []uint64:
if value == nil {
*dst = Int4Array{Status: Null}
} else if len(value) == 0 {
*dst = Int4Array{Status: Present}
} else {
elements := make([]Int4, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int4Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []*uint64:
if value == nil {
*dst = Int4Array{Status: Null}
} else if len(value) == 0 {
*dst = Int4Array{Status: Present}
} else {
elements := make([]Int4, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int4Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []int:
if value == nil {
*dst = Int4Array{Status: Null}
} else if len(value) == 0 {
*dst = Int4Array{Status: Present}
} else {
elements := make([]Int4, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int4Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []*int:
if value == nil {
*dst = Int4Array{Status: Null}
} else if len(value) == 0 {
*dst = Int4Array{Status: Present}
} else {
elements := make([]Int4, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int4Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []uint:
if value == nil {
*dst = Int4Array{Status: Null}
} else if len(value) == 0 {
*dst = Int4Array{Status: Present}
} else {
elements := make([]Int4, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int4Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []*uint:
if value == nil {
*dst = Int4Array{Status: Null}
} else if len(value) == 0 {
*dst = Int4Array{Status: Present}
} else {
elements := make([]Int4, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int4Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []Int4:
if value == nil {
*dst = Int4Array{Status: Null}
} else if len(value) == 0 {
*dst = Int4Array{Status: Present}
} else {
*dst = Int4Array{
Elements: value,
Dimensions: []ArrayDimension{{Length: int32(len(value)), LowerBound: 1}},
Status: Present,
}
}
default:
// Fallback to reflection if an optimised match was not found.
// The reflection is necessary for arrays and multidimensional slices,
// but it comes with a 20-50% performance penalty for large arrays/slices
reflectedValue := reflect.ValueOf(src)
if !reflectedValue.IsValid() || reflectedValue.IsZero() {
*dst = Int4Array{Status: Null}
return nil
}
dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
if !ok {
return fmt.Errorf("cannot find dimensions of %v for Int4Array", src)
}
if elementsLength == 0 {
*dst = Int4Array{Status: Present}
return nil
}
if len(dimensions) == 0 {
if originalSrc, ok := underlyingSliceType(src); ok {
return dst.Set(originalSrc)
}
return fmt.Errorf("cannot convert %v to Int4Array", src)
}
*dst = Int4Array{
Elements: make([]Int4, elementsLength),
Dimensions: dimensions,
Status: Present,
}
elementCount, err := dst.setRecursive(reflectedValue, 0, 0)
if err != nil {
// Maybe the target was one dimension too far, try again:
if len(dst.Dimensions) > 1 {
dst.Dimensions = dst.Dimensions[:len(dst.Dimensions)-1]
elementsLength = 0
for _, dim := range dst.Dimensions {
if elementsLength == 0 {
elementsLength = int(dim.Length)
} else {
elementsLength *= int(dim.Length)
}
}
dst.Elements = make([]Int4, elementsLength)
elementCount, err = dst.setRecursive(reflectedValue, 0, 0)
if err != nil {
return err
}
} else {
return err
}
}
if elementCount != len(dst.Elements) {
return fmt.Errorf("cannot convert %v to Int4Array, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
}
}
return nil
}
func (dst *Int4Array) setRecursive(value reflect.Value, index, dimension int) (int, error) {
switch value.Kind() {
case reflect.Array:
fallthrough
case reflect.Slice:
if len(dst.Dimensions) == dimension {
break
}
valueLen := value.Len()
if int32(valueLen) != dst.Dimensions[dimension].Length {
return 0, fmt.Errorf("multidimensional arrays must have array expressions with matching dimensions")
}
for i := 0; i < valueLen; i++ {
var err error
index, err = dst.setRecursive(value.Index(i), index, dimension+1)
if err != nil {
return 0, err
}
}
return index, nil
}
if !value.CanInterface() {
return 0, fmt.Errorf("cannot convert all values to Int4Array")
}
if err := dst.Elements[index].Set(value.Interface()); err != nil {
return 0, fmt.Errorf("%v in Int4Array", err)
}
index++
return index, nil
}
func (dst Int4Array) Get() interface{} {
switch dst.Status {
case Present:
return dst
case Null:
return nil
default:
return dst.Status
}
}
func (src *Int4Array) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
if len(src.Dimensions) <= 1 {
// Attempt to match to select common types:
switch v := dst.(type) {
case *[]int16:
*v = make([]int16, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]*int16:
*v = make([]*int16, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]uint16:
*v = make([]uint16, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]*uint16:
*v = make([]*uint16, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]int32:
*v = make([]int32, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]*int32:
*v = make([]*int32, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]uint32:
*v = make([]uint32, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]*uint32:
*v = make([]*uint32, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]int64:
*v = make([]int64, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]*int64:
*v = make([]*int64, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]uint64:
*v = make([]uint64, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]*uint64:
*v = make([]*uint64, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]int:
*v = make([]int, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]*int:
*v = make([]*int, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]uint:
*v = make([]uint, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]*uint:
*v = make([]*uint, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
}
}
// Try to convert to something AssignTo can use directly.
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
// Fallback to reflection if an optimised match was not found.
// The reflection is necessary for arrays and multidimensional slices,
// but it comes with a 20-50% performance penalty for large arrays/slices
value := reflect.ValueOf(dst)
if value.Kind() == reflect.Ptr {
value = value.Elem()
}
switch value.Kind() {
case reflect.Array, reflect.Slice:
default:
return fmt.Errorf("cannot assign %T to %T", src, dst)
}
if len(src.Elements) == 0 {
if value.Kind() == reflect.Slice {
value.Set(reflect.MakeSlice(value.Type(), 0, 0))
return nil
}
}
elementCount, err := src.assignToRecursive(value, 0, 0)
if err != nil {
return err
}
if elementCount != len(src.Elements) {
return fmt.Errorf("cannot assign %v, needed to assign %d elements, but only assigned %d", dst, len(src.Elements), elementCount)
}
return nil
case Null:
return NullAssignTo(dst)
}
return fmt.Errorf("cannot decode %#v into %T", src, dst)
}
func (src *Int4Array) assignToRecursive(value reflect.Value, index, dimension int) (int, error) {
switch kind := value.Kind(); kind {
case reflect.Array:
fallthrough
case reflect.Slice:
if len(src.Dimensions) == dimension {
break
}
length := int(src.Dimensions[dimension].Length)
if reflect.Array == kind {
typ := value.Type()
if typ.Len() != length {
return 0, fmt.Errorf("expected size %d array, but %s has size %d array", length, typ, typ.Len())
}
value.Set(reflect.New(typ).Elem())
} else {
value.Set(reflect.MakeSlice(value.Type(), length, length))
}
var err error
for i := 0; i < length; i++ {
index, err = src.assignToRecursive(value.Index(i), index, dimension+1)
if err != nil {
return 0, err
}
}
return index, nil
}
if len(src.Dimensions) != dimension {
return 0, fmt.Errorf("incorrect dimensions, expected %d, found %d", len(src.Dimensions), dimension)
}
if !value.CanAddr() {
return 0, fmt.Errorf("cannot assign all values from Int4Array")
}
addr := value.Addr()
if !addr.CanInterface() {
return 0, fmt.Errorf("cannot assign all values from Int4Array")
}
if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
return 0, err
}
index++
return index, nil
}
func (dst *Int4Array) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Int4Array{Status: Null}
return nil
}
uta, err := ParseUntypedTextArray(string(src))
if err != nil {
return err
}
var elements []Int4
if len(uta.Elements) > 0 {
elements = make([]Int4, len(uta.Elements))
for i, s := range uta.Elements {
var elem Int4
var elemSrc []byte
if s != "NULL" || uta.Quoted[i] {
elemSrc = []byte(s)
}
err = elem.DecodeText(ci, elemSrc)
if err != nil {
return err
}
elements[i] = elem
}
}
*dst = Int4Array{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
return nil
}
func (dst *Int4Array) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Int4Array{Status: Null}
return nil
}
var arrayHeader ArrayHeader
rp, err := arrayHeader.DecodeBinary(ci, src)
if err != nil {
return err
}
if len(arrayHeader.Dimensions) == 0 {
*dst = Int4Array{Dimensions: arrayHeader.Dimensions, Status: Present}
return nil
}
elementCount := arrayHeader.Dimensions[0].Length
for _, d := range arrayHeader.Dimensions[1:] {
elementCount *= d.Length
}
elements := make([]Int4, elementCount)
for i := range elements {
elemLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
rp += 4
var elemSrc []byte
if elemLen >= 0 {
elemSrc = src[rp : rp+elemLen]
rp += elemLen
}
err = elements[i].DecodeBinary(ci, elemSrc)
if err != nil {
return err
}
}
*dst = Int4Array{Elements: elements, Dimensions: arrayHeader.Dimensions, Status: Present}
return nil
}
func (src Int4Array) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
if len(src.Dimensions) == 0 {
return append(buf, '{', '}'), nil
}
buf = EncodeTextArrayDimensions(buf, src.Dimensions)
// dimElemCounts is the multiples of elements that each array lies on. For
// example, a single dimension array of length 4 would have a dimElemCounts of
// [4]. A multi-dimensional array of lengths [3,5,2] would have a
// dimElemCounts of [30,10,2]. This is used to simplify when to render a '{'
// or '}'.
dimElemCounts := make([]int, len(src.Dimensions))
dimElemCounts[len(src.Dimensions)-1] = int(src.Dimensions[len(src.Dimensions)-1].Length)
for i := len(src.Dimensions) - 2; i > -1; i-- {
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
}
inElemBuf := make([]byte, 0, 32)
for i, elem := range src.Elements {
if i > 0 {
buf = append(buf, ',')
}
for _, dec := range dimElemCounts {
if i%dec == 0 {
buf = append(buf, '{')
}
}
elemBuf, err := elem.EncodeText(ci, inElemBuf)
if err != nil {
return nil, err
}
if elemBuf == nil {
buf = append(buf, `NULL`...)
} else {
buf = append(buf, QuoteArrayElementIfNeeded(string(elemBuf))...)
}
for _, dec := range dimElemCounts {
if (i+1)%dec == 0 {
buf = append(buf, '}')
}
}
}
return buf, nil
}
func (src Int4Array) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
arrayHeader := ArrayHeader{
Dimensions: src.Dimensions,
}
if dt, ok := ci.DataTypeForName("int4"); ok {
arrayHeader.ElementOID = int32(dt.OID)
} else {
return nil, fmt.Errorf("unable to find oid for type name %v", "int4")
}
for i := range src.Elements {
if src.Elements[i].Status == Null {
arrayHeader.ContainsNull = true
break
}
}
buf = arrayHeader.EncodeBinary(ci, buf)
for i := range src.Elements {
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
elemBuf, err := src.Elements[i].EncodeBinary(ci, buf)
if err != nil {
return nil, err
}
if elemBuf != nil {
buf = elemBuf
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
}
return buf, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *Int4Array) Scan(src interface{}) error {
if src == nil {
return dst.DecodeText(nil, nil)
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src Int4Array) Value() (driver.Value, error) {
buf, err := src.EncodeText(nil, nil)
if err != nil {
return nil, err
}
if buf == nil {
return nil, nil
}
return string(buf), nil
}
-239
View File
@@ -1,239 +0,0 @@
package pgtype
import (
"database/sql/driver"
"encoding/binary"
"fmt"
"github.com/jackc/pgio"
)
type Int4multirange struct {
Ranges []Int4range
Status Status
}
func (dst *Int4multirange) Set(src interface{}) error {
//untyped nil and typed nil interfaces are different
if src == nil {
*dst = Int4multirange{Status: Null}
return nil
}
switch value := src.(type) {
case Int4multirange:
*dst = value
case *Int4multirange:
*dst = *value
case string:
return dst.DecodeText(nil, []byte(value))
case []Int4range:
if value == nil {
*dst = Int4multirange{Status: Null}
} else if len(value) == 0 {
*dst = Int4multirange{Status: Present}
} else {
elements := make([]Int4range, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int4multirange{
Ranges: elements,
Status: Present,
}
}
case []*Int4range:
if value == nil {
*dst = Int4multirange{Status: Null}
} else if len(value) == 0 {
*dst = Int4multirange{Status: Present}
} else {
elements := make([]Int4range, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int4multirange{
Ranges: elements,
Status: Present,
}
}
default:
return fmt.Errorf("cannot convert %v to Int4multirange", src)
}
return nil
}
func (dst Int4multirange) Get() interface{} {
switch dst.Status {
case Present:
return dst
case Null:
return nil
default:
return dst.Status
}
}
func (src *Int4multirange) AssignTo(dst interface{}) error {
return fmt.Errorf("cannot assign %v to %T", src, dst)
}
func (dst *Int4multirange) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Int4multirange{Status: Null}
return nil
}
utmr, err := ParseUntypedTextMultirange(string(src))
if err != nil {
return err
}
var elements []Int4range
if len(utmr.Elements) > 0 {
elements = make([]Int4range, len(utmr.Elements))
for i, s := range utmr.Elements {
var elem Int4range
elemSrc := []byte(s)
err = elem.DecodeText(ci, elemSrc)
if err != nil {
return err
}
elements[i] = elem
}
}
*dst = Int4multirange{Ranges: elements, Status: Present}
return nil
}
func (dst *Int4multirange) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Int4multirange{Status: Null}
return nil
}
rp := 0
numElems := int(binary.BigEndian.Uint32(src[rp:]))
rp += 4
if numElems == 0 {
*dst = Int4multirange{Status: Present}
return nil
}
elements := make([]Int4range, numElems)
for i := range elements {
elemLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
rp += 4
var elemSrc []byte
if elemLen >= 0 {
elemSrc = src[rp : rp+elemLen]
rp += elemLen
}
err := elements[i].DecodeBinary(ci, elemSrc)
if err != nil {
return err
}
}
*dst = Int4multirange{Ranges: elements, Status: Present}
return nil
}
func (src Int4multirange) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
buf = append(buf, '{')
inElemBuf := make([]byte, 0, 32)
for i, elem := range src.Ranges {
if i > 0 {
buf = append(buf, ',')
}
elemBuf, err := elem.EncodeText(ci, inElemBuf)
if err != nil {
return nil, err
}
if elemBuf == nil {
return nil, fmt.Errorf("multi-range does not allow null range")
} else {
buf = append(buf, string(elemBuf)...)
}
}
buf = append(buf, '}')
return buf, nil
}
func (src Int4multirange) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
buf = pgio.AppendInt32(buf, int32(len(src.Ranges)))
for i := range src.Ranges {
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
elemBuf, err := src.Ranges[i].EncodeBinary(ci, buf)
if err != nil {
return nil, err
}
if elemBuf != nil {
buf = elemBuf
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
}
return buf, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *Int4multirange) Scan(src interface{}) error {
if src == nil {
return dst.DecodeText(nil, nil)
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src Int4multirange) Value() (driver.Value, error) {
return EncodeValueText(src)
}
-267
View File
@@ -1,267 +0,0 @@
package pgtype
import (
"database/sql/driver"
"fmt"
"github.com/jackc/pgio"
)
type Int4range struct {
Lower Int4
Upper Int4
LowerType BoundType
UpperType BoundType
Status Status
}
func (dst *Int4range) Set(src interface{}) error {
// untyped nil and typed nil interfaces are different
if src == nil {
*dst = Int4range{Status: Null}
return nil
}
switch value := src.(type) {
case Int4range:
*dst = value
case *Int4range:
*dst = *value
case string:
return dst.DecodeText(nil, []byte(value))
default:
return fmt.Errorf("cannot convert %v to Int4range", src)
}
return nil
}
func (dst Int4range) Get() interface{} {
switch dst.Status {
case Present:
return dst
case Null:
return nil
default:
return dst.Status
}
}
func (src *Int4range) AssignTo(dst interface{}) error {
return fmt.Errorf("cannot assign %v to %T", src, dst)
}
func (dst *Int4range) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Int4range{Status: Null}
return nil
}
utr, err := ParseUntypedTextRange(string(src))
if err != nil {
return err
}
*dst = Int4range{Status: Present}
dst.LowerType = utr.LowerType
dst.UpperType = utr.UpperType
if dst.LowerType == Empty {
return nil
}
if dst.LowerType == Inclusive || dst.LowerType == Exclusive {
if err := dst.Lower.DecodeText(ci, []byte(utr.Lower)); err != nil {
return err
}
}
if dst.UpperType == Inclusive || dst.UpperType == Exclusive {
if err := dst.Upper.DecodeText(ci, []byte(utr.Upper)); err != nil {
return err
}
}
return nil
}
func (dst *Int4range) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Int4range{Status: Null}
return nil
}
ubr, err := ParseUntypedBinaryRange(src)
if err != nil {
return err
}
*dst = Int4range{Status: Present}
dst.LowerType = ubr.LowerType
dst.UpperType = ubr.UpperType
if dst.LowerType == Empty {
return nil
}
if dst.LowerType == Inclusive || dst.LowerType == Exclusive {
if err := dst.Lower.DecodeBinary(ci, ubr.Lower); err != nil {
return err
}
}
if dst.UpperType == Inclusive || dst.UpperType == Exclusive {
if err := dst.Upper.DecodeBinary(ci, ubr.Upper); err != nil {
return err
}
}
return nil
}
func (src Int4range) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
switch src.LowerType {
case Exclusive, Unbounded:
buf = append(buf, '(')
case Inclusive:
buf = append(buf, '[')
case Empty:
return append(buf, "empty"...), nil
default:
return nil, fmt.Errorf("unknown lower bound type %v", src.LowerType)
}
var err error
if src.LowerType != Unbounded {
buf, err = src.Lower.EncodeText(ci, buf)
if err != nil {
return nil, err
} else if buf == nil {
return nil, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
}
}
buf = append(buf, ',')
if src.UpperType != Unbounded {
buf, err = src.Upper.EncodeText(ci, buf)
if err != nil {
return nil, err
} else if buf == nil {
return nil, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
}
}
switch src.UpperType {
case Exclusive, Unbounded:
buf = append(buf, ')')
case Inclusive:
buf = append(buf, ']')
default:
return nil, fmt.Errorf("unknown upper bound type %v", src.UpperType)
}
return buf, nil
}
func (src Int4range) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
var rangeType byte
switch src.LowerType {
case Inclusive:
rangeType |= lowerInclusiveMask
case Unbounded:
rangeType |= lowerUnboundedMask
case Exclusive:
case Empty:
return append(buf, emptyMask), nil
default:
return nil, fmt.Errorf("unknown LowerType: %v", src.LowerType)
}
switch src.UpperType {
case Inclusive:
rangeType |= upperInclusiveMask
case Unbounded:
rangeType |= upperUnboundedMask
case Exclusive:
default:
return nil, fmt.Errorf("unknown UpperType: %v", src.UpperType)
}
buf = append(buf, rangeType)
var err error
if src.LowerType != Unbounded {
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
buf, err = src.Lower.EncodeBinary(ci, buf)
if err != nil {
return nil, err
}
if buf == nil {
return nil, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
}
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
if src.UpperType != Unbounded {
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
buf, err = src.Upper.EncodeBinary(ci, buf)
if err != nil {
return nil, err
}
if buf == nil {
return nil, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
}
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
return buf, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *Int4range) Scan(src interface{}) error {
if src == nil {
*dst = Int4range{Status: Null}
return nil
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src Int4range) Value() (driver.Value, error) {
return EncodeValueText(src)
}
-298
View File
@@ -1,298 +0,0 @@
package pgtype
import (
"database/sql/driver"
"encoding/binary"
"encoding/json"
"fmt"
"math"
"strconv"
"github.com/jackc/pgio"
)
type Int8 struct {
Int int64
Status Status
}
func (dst *Int8) Set(src interface{}) error {
if src == nil {
*dst = Int8{Status: Null}
return nil
}
if value, ok := src.(interface{ Get() interface{} }); ok {
value2 := value.Get()
if value2 != value {
return dst.Set(value2)
}
}
switch value := src.(type) {
case int8:
*dst = Int8{Int: int64(value), Status: Present}
case uint8:
*dst = Int8{Int: int64(value), Status: Present}
case int16:
*dst = Int8{Int: int64(value), Status: Present}
case uint16:
*dst = Int8{Int: int64(value), Status: Present}
case int32:
*dst = Int8{Int: int64(value), Status: Present}
case uint32:
*dst = Int8{Int: int64(value), Status: Present}
case int64:
*dst = Int8{Int: int64(value), Status: Present}
case uint64:
if value > math.MaxInt64 {
return fmt.Errorf("%d is greater than maximum value for Int8", value)
}
*dst = Int8{Int: int64(value), Status: Present}
case int:
if int64(value) < math.MinInt64 {
return fmt.Errorf("%d is greater than maximum value for Int8", value)
}
if int64(value) > math.MaxInt64 {
return fmt.Errorf("%d is greater than maximum value for Int8", value)
}
*dst = Int8{Int: int64(value), Status: Present}
case uint:
if uint64(value) > math.MaxInt64 {
return fmt.Errorf("%d is greater than maximum value for Int8", value)
}
*dst = Int8{Int: int64(value), Status: Present}
case string:
num, err := strconv.ParseInt(value, 10, 64)
if err != nil {
return err
}
*dst = Int8{Int: num, Status: Present}
case float32:
if value > math.MaxInt64 {
return fmt.Errorf("%f is greater than maximum value for Int8", value)
}
*dst = Int8{Int: int64(value), Status: Present}
case float64:
if value > math.MaxInt64 {
return fmt.Errorf("%f is greater than maximum value for Int8", value)
}
*dst = Int8{Int: int64(value), Status: Present}
case *int8:
if value == nil {
*dst = Int8{Status: Null}
} else {
return dst.Set(*value)
}
case *uint8:
if value == nil {
*dst = Int8{Status: Null}
} else {
return dst.Set(*value)
}
case *int16:
if value == nil {
*dst = Int8{Status: Null}
} else {
return dst.Set(*value)
}
case *uint16:
if value == nil {
*dst = Int8{Status: Null}
} else {
return dst.Set(*value)
}
case *int32:
if value == nil {
*dst = Int8{Status: Null}
} else {
return dst.Set(*value)
}
case *uint32:
if value == nil {
*dst = Int8{Status: Null}
} else {
return dst.Set(*value)
}
case *int64:
if value == nil {
*dst = Int8{Status: Null}
} else {
return dst.Set(*value)
}
case *uint64:
if value == nil {
*dst = Int8{Status: Null}
} else {
return dst.Set(*value)
}
case *int:
if value == nil {
*dst = Int8{Status: Null}
} else {
return dst.Set(*value)
}
case *uint:
if value == nil {
*dst = Int8{Status: Null}
} else {
return dst.Set(*value)
}
case *string:
if value == nil {
*dst = Int8{Status: Null}
} else {
return dst.Set(*value)
}
case *float32:
if value == nil {
*dst = Int8{Status: Null}
} else {
return dst.Set(*value)
}
case *float64:
if value == nil {
*dst = Int8{Status: Null}
} else {
return dst.Set(*value)
}
default:
if originalSrc, ok := underlyingNumberType(src); ok {
return dst.Set(originalSrc)
}
return fmt.Errorf("cannot convert %v to Int8", value)
}
return nil
}
func (dst Int8) Get() interface{} {
switch dst.Status {
case Present:
return dst.Int
case Null:
return nil
default:
return dst.Status
}
}
func (src *Int8) AssignTo(dst interface{}) error {
return int64AssignTo(int64(src.Int), src.Status, dst)
}
func (dst *Int8) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Int8{Status: Null}
return nil
}
n, err := strconv.ParseInt(string(src), 10, 64)
if err != nil {
return err
}
*dst = Int8{Int: n, Status: Present}
return nil
}
func (dst *Int8) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Int8{Status: Null}
return nil
}
if len(src) != 8 {
return fmt.Errorf("invalid length for int8: %v", len(src))
}
n := int64(binary.BigEndian.Uint64(src))
*dst = Int8{Int: n, Status: Present}
return nil
}
func (src Int8) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
return append(buf, strconv.FormatInt(src.Int, 10)...), nil
}
func (src Int8) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
return pgio.AppendInt64(buf, src.Int), nil
}
// Scan implements the database/sql Scanner interface.
func (dst *Int8) Scan(src interface{}) error {
if src == nil {
*dst = Int8{Status: Null}
return nil
}
switch src := src.(type) {
case int64:
*dst = Int8{Int: src, Status: Present}
return nil
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src Int8) Value() (driver.Value, error) {
switch src.Status {
case Present:
return int64(src.Int), nil
case Null:
return nil, nil
default:
return nil, errUndefined
}
}
func (src Int8) MarshalJSON() ([]byte, error) {
switch src.Status {
case Present:
return []byte(strconv.FormatInt(src.Int, 10)), nil
case Null:
return []byte("null"), nil
case Undefined:
return nil, errUndefined
}
return nil, errBadStatus
}
func (dst *Int8) UnmarshalJSON(b []byte) error {
var n *int64
err := json.Unmarshal(b, &n)
if err != nil {
return err
}
if n == nil {
*dst = Int8{Status: Null}
} else {
*dst = Int8{Int: *n, Status: Present}
}
return nil
}
-909
View File
@@ -1,909 +0,0 @@
// Code generated by erb. DO NOT EDIT.
package pgtype
import (
"database/sql/driver"
"encoding/binary"
"fmt"
"reflect"
"github.com/jackc/pgio"
)
type Int8Array struct {
Elements []Int8
Dimensions []ArrayDimension
Status Status
}
func (dst *Int8Array) Set(src interface{}) error {
// untyped nil and typed nil interfaces are different
if src == nil {
*dst = Int8Array{Status: Null}
return nil
}
if value, ok := src.(interface{ Get() interface{} }); ok {
value2 := value.Get()
if value2 != value {
return dst.Set(value2)
}
}
// Attempt to match to select common types:
switch value := src.(type) {
case []int16:
if value == nil {
*dst = Int8Array{Status: Null}
} else if len(value) == 0 {
*dst = Int8Array{Status: Present}
} else {
elements := make([]Int8, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int8Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []*int16:
if value == nil {
*dst = Int8Array{Status: Null}
} else if len(value) == 0 {
*dst = Int8Array{Status: Present}
} else {
elements := make([]Int8, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int8Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []uint16:
if value == nil {
*dst = Int8Array{Status: Null}
} else if len(value) == 0 {
*dst = Int8Array{Status: Present}
} else {
elements := make([]Int8, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int8Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []*uint16:
if value == nil {
*dst = Int8Array{Status: Null}
} else if len(value) == 0 {
*dst = Int8Array{Status: Present}
} else {
elements := make([]Int8, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int8Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []int32:
if value == nil {
*dst = Int8Array{Status: Null}
} else if len(value) == 0 {
*dst = Int8Array{Status: Present}
} else {
elements := make([]Int8, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int8Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []*int32:
if value == nil {
*dst = Int8Array{Status: Null}
} else if len(value) == 0 {
*dst = Int8Array{Status: Present}
} else {
elements := make([]Int8, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int8Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []uint32:
if value == nil {
*dst = Int8Array{Status: Null}
} else if len(value) == 0 {
*dst = Int8Array{Status: Present}
} else {
elements := make([]Int8, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int8Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []*uint32:
if value == nil {
*dst = Int8Array{Status: Null}
} else if len(value) == 0 {
*dst = Int8Array{Status: Present}
} else {
elements := make([]Int8, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int8Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []int64:
if value == nil {
*dst = Int8Array{Status: Null}
} else if len(value) == 0 {
*dst = Int8Array{Status: Present}
} else {
elements := make([]Int8, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int8Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []*int64:
if value == nil {
*dst = Int8Array{Status: Null}
} else if len(value) == 0 {
*dst = Int8Array{Status: Present}
} else {
elements := make([]Int8, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int8Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []uint64:
if value == nil {
*dst = Int8Array{Status: Null}
} else if len(value) == 0 {
*dst = Int8Array{Status: Present}
} else {
elements := make([]Int8, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int8Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []*uint64:
if value == nil {
*dst = Int8Array{Status: Null}
} else if len(value) == 0 {
*dst = Int8Array{Status: Present}
} else {
elements := make([]Int8, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int8Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []int:
if value == nil {
*dst = Int8Array{Status: Null}
} else if len(value) == 0 {
*dst = Int8Array{Status: Present}
} else {
elements := make([]Int8, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int8Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []*int:
if value == nil {
*dst = Int8Array{Status: Null}
} else if len(value) == 0 {
*dst = Int8Array{Status: Present}
} else {
elements := make([]Int8, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int8Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []uint:
if value == nil {
*dst = Int8Array{Status: Null}
} else if len(value) == 0 {
*dst = Int8Array{Status: Present}
} else {
elements := make([]Int8, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int8Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []*uint:
if value == nil {
*dst = Int8Array{Status: Null}
} else if len(value) == 0 {
*dst = Int8Array{Status: Present}
} else {
elements := make([]Int8, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int8Array{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []Int8:
if value == nil {
*dst = Int8Array{Status: Null}
} else if len(value) == 0 {
*dst = Int8Array{Status: Present}
} else {
*dst = Int8Array{
Elements: value,
Dimensions: []ArrayDimension{{Length: int32(len(value)), LowerBound: 1}},
Status: Present,
}
}
default:
// Fallback to reflection if an optimised match was not found.
// The reflection is necessary for arrays and multidimensional slices,
// but it comes with a 20-50% performance penalty for large arrays/slices
reflectedValue := reflect.ValueOf(src)
if !reflectedValue.IsValid() || reflectedValue.IsZero() {
*dst = Int8Array{Status: Null}
return nil
}
dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
if !ok {
return fmt.Errorf("cannot find dimensions of %v for Int8Array", src)
}
if elementsLength == 0 {
*dst = Int8Array{Status: Present}
return nil
}
if len(dimensions) == 0 {
if originalSrc, ok := underlyingSliceType(src); ok {
return dst.Set(originalSrc)
}
return fmt.Errorf("cannot convert %v to Int8Array", src)
}
*dst = Int8Array{
Elements: make([]Int8, elementsLength),
Dimensions: dimensions,
Status: Present,
}
elementCount, err := dst.setRecursive(reflectedValue, 0, 0)
if err != nil {
// Maybe the target was one dimension too far, try again:
if len(dst.Dimensions) > 1 {
dst.Dimensions = dst.Dimensions[:len(dst.Dimensions)-1]
elementsLength = 0
for _, dim := range dst.Dimensions {
if elementsLength == 0 {
elementsLength = int(dim.Length)
} else {
elementsLength *= int(dim.Length)
}
}
dst.Elements = make([]Int8, elementsLength)
elementCount, err = dst.setRecursive(reflectedValue, 0, 0)
if err != nil {
return err
}
} else {
return err
}
}
if elementCount != len(dst.Elements) {
return fmt.Errorf("cannot convert %v to Int8Array, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
}
}
return nil
}
func (dst *Int8Array) setRecursive(value reflect.Value, index, dimension int) (int, error) {
switch value.Kind() {
case reflect.Array:
fallthrough
case reflect.Slice:
if len(dst.Dimensions) == dimension {
break
}
valueLen := value.Len()
if int32(valueLen) != dst.Dimensions[dimension].Length {
return 0, fmt.Errorf("multidimensional arrays must have array expressions with matching dimensions")
}
for i := 0; i < valueLen; i++ {
var err error
index, err = dst.setRecursive(value.Index(i), index, dimension+1)
if err != nil {
return 0, err
}
}
return index, nil
}
if !value.CanInterface() {
return 0, fmt.Errorf("cannot convert all values to Int8Array")
}
if err := dst.Elements[index].Set(value.Interface()); err != nil {
return 0, fmt.Errorf("%v in Int8Array", err)
}
index++
return index, nil
}
func (dst Int8Array) Get() interface{} {
switch dst.Status {
case Present:
return dst
case Null:
return nil
default:
return dst.Status
}
}
func (src *Int8Array) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
if len(src.Dimensions) <= 1 {
// Attempt to match to select common types:
switch v := dst.(type) {
case *[]int16:
*v = make([]int16, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]*int16:
*v = make([]*int16, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]uint16:
*v = make([]uint16, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]*uint16:
*v = make([]*uint16, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]int32:
*v = make([]int32, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]*int32:
*v = make([]*int32, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]uint32:
*v = make([]uint32, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]*uint32:
*v = make([]*uint32, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]int64:
*v = make([]int64, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]*int64:
*v = make([]*int64, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]uint64:
*v = make([]uint64, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]*uint64:
*v = make([]*uint64, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]int:
*v = make([]int, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]*int:
*v = make([]*int, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]uint:
*v = make([]uint, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]*uint:
*v = make([]*uint, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
}
}
// Try to convert to something AssignTo can use directly.
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
// Fallback to reflection if an optimised match was not found.
// The reflection is necessary for arrays and multidimensional slices,
// but it comes with a 20-50% performance penalty for large arrays/slices
value := reflect.ValueOf(dst)
if value.Kind() == reflect.Ptr {
value = value.Elem()
}
switch value.Kind() {
case reflect.Array, reflect.Slice:
default:
return fmt.Errorf("cannot assign %T to %T", src, dst)
}
if len(src.Elements) == 0 {
if value.Kind() == reflect.Slice {
value.Set(reflect.MakeSlice(value.Type(), 0, 0))
return nil
}
}
elementCount, err := src.assignToRecursive(value, 0, 0)
if err != nil {
return err
}
if elementCount != len(src.Elements) {
return fmt.Errorf("cannot assign %v, needed to assign %d elements, but only assigned %d", dst, len(src.Elements), elementCount)
}
return nil
case Null:
return NullAssignTo(dst)
}
return fmt.Errorf("cannot decode %#v into %T", src, dst)
}
func (src *Int8Array) assignToRecursive(value reflect.Value, index, dimension int) (int, error) {
switch kind := value.Kind(); kind {
case reflect.Array:
fallthrough
case reflect.Slice:
if len(src.Dimensions) == dimension {
break
}
length := int(src.Dimensions[dimension].Length)
if reflect.Array == kind {
typ := value.Type()
if typ.Len() != length {
return 0, fmt.Errorf("expected size %d array, but %s has size %d array", length, typ, typ.Len())
}
value.Set(reflect.New(typ).Elem())
} else {
value.Set(reflect.MakeSlice(value.Type(), length, length))
}
var err error
for i := 0; i < length; i++ {
index, err = src.assignToRecursive(value.Index(i), index, dimension+1)
if err != nil {
return 0, err
}
}
return index, nil
}
if len(src.Dimensions) != dimension {
return 0, fmt.Errorf("incorrect dimensions, expected %d, found %d", len(src.Dimensions), dimension)
}
if !value.CanAddr() {
return 0, fmt.Errorf("cannot assign all values from Int8Array")
}
addr := value.Addr()
if !addr.CanInterface() {
return 0, fmt.Errorf("cannot assign all values from Int8Array")
}
if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
return 0, err
}
index++
return index, nil
}
func (dst *Int8Array) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Int8Array{Status: Null}
return nil
}
uta, err := ParseUntypedTextArray(string(src))
if err != nil {
return err
}
var elements []Int8
if len(uta.Elements) > 0 {
elements = make([]Int8, len(uta.Elements))
for i, s := range uta.Elements {
var elem Int8
var elemSrc []byte
if s != "NULL" || uta.Quoted[i] {
elemSrc = []byte(s)
}
err = elem.DecodeText(ci, elemSrc)
if err != nil {
return err
}
elements[i] = elem
}
}
*dst = Int8Array{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
return nil
}
func (dst *Int8Array) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Int8Array{Status: Null}
return nil
}
var arrayHeader ArrayHeader
rp, err := arrayHeader.DecodeBinary(ci, src)
if err != nil {
return err
}
if len(arrayHeader.Dimensions) == 0 {
*dst = Int8Array{Dimensions: arrayHeader.Dimensions, Status: Present}
return nil
}
elementCount := arrayHeader.Dimensions[0].Length
for _, d := range arrayHeader.Dimensions[1:] {
elementCount *= d.Length
}
elements := make([]Int8, elementCount)
for i := range elements {
elemLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
rp += 4
var elemSrc []byte
if elemLen >= 0 {
elemSrc = src[rp : rp+elemLen]
rp += elemLen
}
err = elements[i].DecodeBinary(ci, elemSrc)
if err != nil {
return err
}
}
*dst = Int8Array{Elements: elements, Dimensions: arrayHeader.Dimensions, Status: Present}
return nil
}
func (src Int8Array) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
if len(src.Dimensions) == 0 {
return append(buf, '{', '}'), nil
}
buf = EncodeTextArrayDimensions(buf, src.Dimensions)
// dimElemCounts is the multiples of elements that each array lies on. For
// example, a single dimension array of length 4 would have a dimElemCounts of
// [4]. A multi-dimensional array of lengths [3,5,2] would have a
// dimElemCounts of [30,10,2]. This is used to simplify when to render a '{'
// or '}'.
dimElemCounts := make([]int, len(src.Dimensions))
dimElemCounts[len(src.Dimensions)-1] = int(src.Dimensions[len(src.Dimensions)-1].Length)
for i := len(src.Dimensions) - 2; i > -1; i-- {
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
}
inElemBuf := make([]byte, 0, 32)
for i, elem := range src.Elements {
if i > 0 {
buf = append(buf, ',')
}
for _, dec := range dimElemCounts {
if i%dec == 0 {
buf = append(buf, '{')
}
}
elemBuf, err := elem.EncodeText(ci, inElemBuf)
if err != nil {
return nil, err
}
if elemBuf == nil {
buf = append(buf, `NULL`...)
} else {
buf = append(buf, QuoteArrayElementIfNeeded(string(elemBuf))...)
}
for _, dec := range dimElemCounts {
if (i+1)%dec == 0 {
buf = append(buf, '}')
}
}
}
return buf, nil
}
func (src Int8Array) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
arrayHeader := ArrayHeader{
Dimensions: src.Dimensions,
}
if dt, ok := ci.DataTypeForName("int8"); ok {
arrayHeader.ElementOID = int32(dt.OID)
} else {
return nil, fmt.Errorf("unable to find oid for type name %v", "int8")
}
for i := range src.Elements {
if src.Elements[i].Status == Null {
arrayHeader.ContainsNull = true
break
}
}
buf = arrayHeader.EncodeBinary(ci, buf)
for i := range src.Elements {
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
elemBuf, err := src.Elements[i].EncodeBinary(ci, buf)
if err != nil {
return nil, err
}
if elemBuf != nil {
buf = elemBuf
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
}
return buf, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *Int8Array) Scan(src interface{}) error {
if src == nil {
return dst.DecodeText(nil, nil)
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src Int8Array) Value() (driver.Value, error) {
buf, err := src.EncodeText(nil, nil)
if err != nil {
return nil, err
}
if buf == nil {
return nil, nil
}
return string(buf), nil
}
-239
View File
@@ -1,239 +0,0 @@
package pgtype
import (
"database/sql/driver"
"encoding/binary"
"fmt"
"github.com/jackc/pgio"
)
type Int8multirange struct {
Ranges []Int8range
Status Status
}
func (dst *Int8multirange) Set(src interface{}) error {
//untyped nil and typed nil interfaces are different
if src == nil {
*dst = Int8multirange{Status: Null}
return nil
}
switch value := src.(type) {
case Int8multirange:
*dst = value
case *Int8multirange:
*dst = *value
case string:
return dst.DecodeText(nil, []byte(value))
case []Int8range:
if value == nil {
*dst = Int8multirange{Status: Null}
} else if len(value) == 0 {
*dst = Int8multirange{Status: Present}
} else {
elements := make([]Int8range, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int8multirange{
Ranges: elements,
Status: Present,
}
}
case []*Int8range:
if value == nil {
*dst = Int8multirange{Status: Null}
} else if len(value) == 0 {
*dst = Int8multirange{Status: Present}
} else {
elements := make([]Int8range, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Int8multirange{
Ranges: elements,
Status: Present,
}
}
default:
return fmt.Errorf("cannot convert %v to Int8multirange", src)
}
return nil
}
func (dst Int8multirange) Get() interface{} {
switch dst.Status {
case Present:
return dst
case Null:
return nil
default:
return dst.Status
}
}
func (src *Int8multirange) AssignTo(dst interface{}) error {
return fmt.Errorf("cannot assign %v to %T", src, dst)
}
func (dst *Int8multirange) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Int8multirange{Status: Null}
return nil
}
utmr, err := ParseUntypedTextMultirange(string(src))
if err != nil {
return err
}
var elements []Int8range
if len(utmr.Elements) > 0 {
elements = make([]Int8range, len(utmr.Elements))
for i, s := range utmr.Elements {
var elem Int8range
elemSrc := []byte(s)
err = elem.DecodeText(ci, elemSrc)
if err != nil {
return err
}
elements[i] = elem
}
}
*dst = Int8multirange{Ranges: elements, Status: Present}
return nil
}
func (dst *Int8multirange) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Int8multirange{Status: Null}
return nil
}
rp := 0
numElems := int(binary.BigEndian.Uint32(src[rp:]))
rp += 4
if numElems == 0 {
*dst = Int8multirange{Status: Present}
return nil
}
elements := make([]Int8range, numElems)
for i := range elements {
elemLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
rp += 4
var elemSrc []byte
if elemLen >= 0 {
elemSrc = src[rp : rp+elemLen]
rp += elemLen
}
err := elements[i].DecodeBinary(ci, elemSrc)
if err != nil {
return err
}
}
*dst = Int8multirange{Ranges: elements, Status: Present}
return nil
}
func (src Int8multirange) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
buf = append(buf, '{')
inElemBuf := make([]byte, 0, 32)
for i, elem := range src.Ranges {
if i > 0 {
buf = append(buf, ',')
}
elemBuf, err := elem.EncodeText(ci, inElemBuf)
if err != nil {
return nil, err
}
if elemBuf == nil {
return nil, fmt.Errorf("multi-range does not allow null range")
} else {
buf = append(buf, string(elemBuf)...)
}
}
buf = append(buf, '}')
return buf, nil
}
func (src Int8multirange) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
buf = pgio.AppendInt32(buf, int32(len(src.Ranges)))
for i := range src.Ranges {
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
elemBuf, err := src.Ranges[i].EncodeBinary(ci, buf)
if err != nil {
return nil, err
}
if elemBuf != nil {
buf = elemBuf
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
}
return buf, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *Int8multirange) Scan(src interface{}) error {
if src == nil {
return dst.DecodeText(nil, nil)
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src Int8multirange) Value() (driver.Value, error) {
return EncodeValueText(src)
}
-267
View File
@@ -1,267 +0,0 @@
package pgtype
import (
"database/sql/driver"
"fmt"
"github.com/jackc/pgio"
)
type Int8range struct {
Lower Int8
Upper Int8
LowerType BoundType
UpperType BoundType
Status Status
}
func (dst *Int8range) Set(src interface{}) error {
// untyped nil and typed nil interfaces are different
if src == nil {
*dst = Int8range{Status: Null}
return nil
}
switch value := src.(type) {
case Int8range:
*dst = value
case *Int8range:
*dst = *value
case string:
return dst.DecodeText(nil, []byte(value))
default:
return fmt.Errorf("cannot convert %v to Int8range", src)
}
return nil
}
func (dst Int8range) Get() interface{} {
switch dst.Status {
case Present:
return dst
case Null:
return nil
default:
return dst.Status
}
}
func (src *Int8range) AssignTo(dst interface{}) error {
return fmt.Errorf("cannot assign %v to %T", src, dst)
}
func (dst *Int8range) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Int8range{Status: Null}
return nil
}
utr, err := ParseUntypedTextRange(string(src))
if err != nil {
return err
}
*dst = Int8range{Status: Present}
dst.LowerType = utr.LowerType
dst.UpperType = utr.UpperType
if dst.LowerType == Empty {
return nil
}
if dst.LowerType == Inclusive || dst.LowerType == Exclusive {
if err := dst.Lower.DecodeText(ci, []byte(utr.Lower)); err != nil {
return err
}
}
if dst.UpperType == Inclusive || dst.UpperType == Exclusive {
if err := dst.Upper.DecodeText(ci, []byte(utr.Upper)); err != nil {
return err
}
}
return nil
}
func (dst *Int8range) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Int8range{Status: Null}
return nil
}
ubr, err := ParseUntypedBinaryRange(src)
if err != nil {
return err
}
*dst = Int8range{Status: Present}
dst.LowerType = ubr.LowerType
dst.UpperType = ubr.UpperType
if dst.LowerType == Empty {
return nil
}
if dst.LowerType == Inclusive || dst.LowerType == Exclusive {
if err := dst.Lower.DecodeBinary(ci, ubr.Lower); err != nil {
return err
}
}
if dst.UpperType == Inclusive || dst.UpperType == Exclusive {
if err := dst.Upper.DecodeBinary(ci, ubr.Upper); err != nil {
return err
}
}
return nil
}
func (src Int8range) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
switch src.LowerType {
case Exclusive, Unbounded:
buf = append(buf, '(')
case Inclusive:
buf = append(buf, '[')
case Empty:
return append(buf, "empty"...), nil
default:
return nil, fmt.Errorf("unknown lower bound type %v", src.LowerType)
}
var err error
if src.LowerType != Unbounded {
buf, err = src.Lower.EncodeText(ci, buf)
if err != nil {
return nil, err
} else if buf == nil {
return nil, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
}
}
buf = append(buf, ',')
if src.UpperType != Unbounded {
buf, err = src.Upper.EncodeText(ci, buf)
if err != nil {
return nil, err
} else if buf == nil {
return nil, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
}
}
switch src.UpperType {
case Exclusive, Unbounded:
buf = append(buf, ')')
case Inclusive:
buf = append(buf, ']')
default:
return nil, fmt.Errorf("unknown upper bound type %v", src.UpperType)
}
return buf, nil
}
func (src Int8range) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
var rangeType byte
switch src.LowerType {
case Inclusive:
rangeType |= lowerInclusiveMask
case Unbounded:
rangeType |= lowerUnboundedMask
case Exclusive:
case Empty:
return append(buf, emptyMask), nil
default:
return nil, fmt.Errorf("unknown LowerType: %v", src.LowerType)
}
switch src.UpperType {
case Inclusive:
rangeType |= upperInclusiveMask
case Unbounded:
rangeType |= upperUnboundedMask
case Exclusive:
default:
return nil, fmt.Errorf("unknown UpperType: %v", src.UpperType)
}
buf = append(buf, rangeType)
var err error
if src.LowerType != Unbounded {
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
buf, err = src.Lower.EncodeBinary(ci, buf)
if err != nil {
return nil, err
}
if buf == nil {
return nil, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
}
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
if src.UpperType != Unbounded {
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
buf, err = src.Upper.EncodeBinary(ci, buf)
if err != nil {
return nil, err
}
if buf == nil {
return nil, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
}
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
return buf, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *Int8range) Scan(src interface{}) error {
if src == nil {
*dst = Int8range{Status: Null}
return nil
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src Int8range) Value() (driver.Value, error) {
return EncodeValueText(src)
}
-257
View File
@@ -1,257 +0,0 @@
package pgtype
import (
"database/sql/driver"
"encoding/binary"
"fmt"
"strconv"
"strings"
"time"
"github.com/jackc/pgio"
)
const (
microsecondsPerSecond = 1000000
microsecondsPerMinute = 60 * microsecondsPerSecond
microsecondsPerHour = 60 * microsecondsPerMinute
microsecondsPerDay = 24 * microsecondsPerHour
microsecondsPerMonth = 30 * microsecondsPerDay
)
type Interval struct {
Microseconds int64
Days int32
Months int32
Status Status
}
func (dst *Interval) Set(src interface{}) error {
if src == nil {
*dst = Interval{Status: Null}
return nil
}
if value, ok := src.(interface{ Get() interface{} }); ok {
value2 := value.Get()
if value2 != value {
return dst.Set(value2)
}
}
switch value := src.(type) {
case time.Duration:
*dst = Interval{Microseconds: int64(value) / 1000, Status: Present}
default:
if originalSrc, ok := underlyingPtrType(src); ok {
return dst.Set(originalSrc)
}
return fmt.Errorf("cannot convert %v to Interval", value)
}
return nil
}
func (dst Interval) Get() interface{} {
switch dst.Status {
case Present:
return dst
case Null:
return nil
default:
return dst.Status
}
}
func (src *Interval) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
switch v := dst.(type) {
case *time.Duration:
us := int64(src.Months)*microsecondsPerMonth + int64(src.Days)*microsecondsPerDay + src.Microseconds
*v = time.Duration(us) * time.Microsecond
return nil
default:
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
return fmt.Errorf("unable to assign to %T", dst)
}
case Null:
return NullAssignTo(dst)
}
return fmt.Errorf("cannot decode %#v into %T", src, dst)
}
func (dst *Interval) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Interval{Status: Null}
return nil
}
var microseconds int64
var days int32
var months int32
parts := strings.Split(string(src), " ")
for i := 0; i < len(parts)-1; i += 2 {
scalar, err := strconv.ParseInt(parts[i], 10, 64)
if err != nil {
return fmt.Errorf("bad interval format")
}
switch parts[i+1] {
case "year", "years":
months += int32(scalar * 12)
case "mon", "mons":
months += int32(scalar)
case "day", "days":
days = int32(scalar)
}
}
if len(parts)%2 == 1 {
timeParts := strings.SplitN(parts[len(parts)-1], ":", 3)
if len(timeParts) != 3 {
return fmt.Errorf("bad interval format")
}
var negative bool
if timeParts[0][0] == '-' {
negative = true
timeParts[0] = timeParts[0][1:]
}
hours, err := strconv.ParseInt(timeParts[0], 10, 64)
if err != nil {
return fmt.Errorf("bad interval hour format: %s", timeParts[0])
}
minutes, err := strconv.ParseInt(timeParts[1], 10, 64)
if err != nil {
return fmt.Errorf("bad interval minute format: %s", timeParts[1])
}
secondParts := strings.SplitN(timeParts[2], ".", 2)
seconds, err := strconv.ParseInt(secondParts[0], 10, 64)
if err != nil {
return fmt.Errorf("bad interval second format: %s", secondParts[0])
}
var uSeconds int64
if len(secondParts) == 2 {
uSeconds, err = strconv.ParseInt(secondParts[1], 10, 64)
if err != nil {
return fmt.Errorf("bad interval decimal format: %s", secondParts[1])
}
for i := 0; i < 6-len(secondParts[1]); i++ {
uSeconds *= 10
}
}
microseconds = hours * microsecondsPerHour
microseconds += minutes * microsecondsPerMinute
microseconds += seconds * microsecondsPerSecond
microseconds += uSeconds
if negative {
microseconds = -microseconds
}
}
*dst = Interval{Months: months, Days: days, Microseconds: microseconds, Status: Present}
return nil
}
func (dst *Interval) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Interval{Status: Null}
return nil
}
if len(src) != 16 {
return fmt.Errorf("Received an invalid size for an interval: %d", len(src))
}
microseconds := int64(binary.BigEndian.Uint64(src))
days := int32(binary.BigEndian.Uint32(src[8:]))
months := int32(binary.BigEndian.Uint32(src[12:]))
*dst = Interval{Microseconds: microseconds, Days: days, Months: months, Status: Present}
return nil
}
func (src Interval) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
if src.Months != 0 {
buf = append(buf, strconv.FormatInt(int64(src.Months), 10)...)
buf = append(buf, " mon "...)
}
if src.Days != 0 {
buf = append(buf, strconv.FormatInt(int64(src.Days), 10)...)
buf = append(buf, " day "...)
}
absMicroseconds := src.Microseconds
if absMicroseconds < 0 {
absMicroseconds = -absMicroseconds
buf = append(buf, '-')
}
hours := absMicroseconds / microsecondsPerHour
minutes := (absMicroseconds % microsecondsPerHour) / microsecondsPerMinute
seconds := (absMicroseconds % microsecondsPerMinute) / microsecondsPerSecond
microseconds := absMicroseconds % microsecondsPerSecond
timeStr := fmt.Sprintf("%02d:%02d:%02d.%06d", hours, minutes, seconds, microseconds)
return append(buf, timeStr...), nil
}
// EncodeBinary encodes src into w.
func (src Interval) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
buf = pgio.AppendInt64(buf, src.Microseconds)
buf = pgio.AppendInt32(buf, src.Days)
return pgio.AppendInt32(buf, src.Months), nil
}
// Scan implements the database/sql Scanner interface.
func (dst *Interval) Scan(src interface{}) error {
if src == nil {
*dst = Interval{Status: Null}
return nil
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src Interval) Value() (driver.Value, error) {
return EncodeValueText(src)
}
-205
View File
@@ -1,205 +0,0 @@
package pgtype
import (
"database/sql/driver"
"encoding/json"
"errors"
"fmt"
)
type JSON struct {
Bytes []byte
Status Status
}
func (dst *JSON) Set(src interface{}) error {
if src == nil {
*dst = JSON{Status: Null}
return nil
}
if value, ok := src.(interface{ Get() interface{} }); ok {
value2 := value.Get()
if value2 != value {
return dst.Set(value2)
}
}
switch value := src.(type) {
case string:
*dst = JSON{Bytes: []byte(value), Status: Present}
case *string:
if value == nil {
*dst = JSON{Status: Null}
} else {
*dst = JSON{Bytes: []byte(*value), Status: Present}
}
case []byte:
if value == nil {
*dst = JSON{Status: Null}
} else {
*dst = JSON{Bytes: value, Status: Present}
}
// Encode* methods are defined on *JSON. If JSON is passed directly then the
// struct itself would be encoded instead of Bytes. This is clearly a footgun
// so detect and return an error. See https://github.com/jackc/pgx/issues/350.
case JSON:
return errors.New("use pointer to pgtype.JSON instead of value")
// Same as above but for JSONB (because they share implementation)
case JSONB:
return errors.New("use pointer to pgtype.JSONB instead of value")
default:
buf, err := json.Marshal(value)
if err != nil {
return err
}
*dst = JSON{Bytes: buf, Status: Present}
}
return nil
}
func (dst JSON) Get() interface{} {
switch dst.Status {
case Present:
var i interface{}
err := json.Unmarshal(dst.Bytes, &i)
if err != nil {
return dst
}
return i
case Null:
return nil
default:
return dst.Status
}
}
func (src *JSON) AssignTo(dst interface{}) error {
switch v := dst.(type) {
case *string:
if src.Status == Present {
*v = string(src.Bytes)
} else {
return fmt.Errorf("cannot assign non-present status to %T", dst)
}
case **string:
if src.Status == Present {
s := string(src.Bytes)
*v = &s
return nil
} else {
*v = nil
return nil
}
case *[]byte:
if src.Status != Present {
*v = nil
} else {
buf := make([]byte, len(src.Bytes))
copy(buf, src.Bytes)
*v = buf
}
default:
data := src.Bytes
if data == nil || src.Status != Present {
data = []byte("null")
}
return json.Unmarshal(data, dst)
}
return nil
}
func (JSON) PreferredResultFormat() int16 {
return TextFormatCode
}
func (dst *JSON) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = JSON{Status: Null}
return nil
}
*dst = JSON{Bytes: src, Status: Present}
return nil
}
func (dst *JSON) DecodeBinary(ci *ConnInfo, src []byte) error {
return dst.DecodeText(ci, src)
}
func (JSON) PreferredParamFormat() int16 {
return TextFormatCode
}
func (src JSON) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
return append(buf, src.Bytes...), nil
}
func (src JSON) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
return src.EncodeText(ci, buf)
}
// Scan implements the database/sql Scanner interface.
func (dst *JSON) Scan(src interface{}) error {
if src == nil {
*dst = JSON{Status: Null}
return nil
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src JSON) Value() (driver.Value, error) {
switch src.Status {
case Present:
return src.Bytes, nil
case Null:
return nil, nil
default:
return nil, errUndefined
}
}
func (src JSON) MarshalJSON() ([]byte, error) {
switch src.Status {
case Present:
return src.Bytes, nil
case Null:
return []byte("null"), nil
case Undefined:
return nil, errUndefined
}
return nil, errBadStatus
}
func (dst *JSON) UnmarshalJSON(b []byte) error {
if b == nil || string(b) == "null" {
*dst = JSON{Status: Null}
} else {
*dst = JSON{Bytes: b, Status: Present}
}
return nil
}
-546
View File
@@ -1,546 +0,0 @@
// Code generated by erb. DO NOT EDIT.
package pgtype
import (
"database/sql/driver"
"encoding/binary"
"encoding/json"
"fmt"
"reflect"
"github.com/jackc/pgio"
)
type JSONArray struct {
Elements []JSON
Dimensions []ArrayDimension
Status Status
}
func (dst *JSONArray) Set(src interface{}) error {
// untyped nil and typed nil interfaces are different
if src == nil {
*dst = JSONArray{Status: Null}
return nil
}
if value, ok := src.(interface{ Get() interface{} }); ok {
value2 := value.Get()
if value2 != value {
return dst.Set(value2)
}
}
// Attempt to match to select common types:
switch value := src.(type) {
case []string:
if value == nil {
*dst = JSONArray{Status: Null}
} else if len(value) == 0 {
*dst = JSONArray{Status: Present}
} else {
elements := make([]JSON, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = JSONArray{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case [][]byte:
if value == nil {
*dst = JSONArray{Status: Null}
} else if len(value) == 0 {
*dst = JSONArray{Status: Present}
} else {
elements := make([]JSON, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = JSONArray{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []json.RawMessage:
if value == nil {
*dst = JSONArray{Status: Null}
} else if len(value) == 0 {
*dst = JSONArray{Status: Present}
} else {
elements := make([]JSON, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = JSONArray{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []JSON:
if value == nil {
*dst = JSONArray{Status: Null}
} else if len(value) == 0 {
*dst = JSONArray{Status: Present}
} else {
*dst = JSONArray{
Elements: value,
Dimensions: []ArrayDimension{{Length: int32(len(value)), LowerBound: 1}},
Status: Present,
}
}
default:
// Fallback to reflection if an optimised match was not found.
// The reflection is necessary for arrays and multidimensional slices,
// but it comes with a 20-50% performance penalty for large arrays/slices
reflectedValue := reflect.ValueOf(src)
if !reflectedValue.IsValid() || reflectedValue.IsZero() {
*dst = JSONArray{Status: Null}
return nil
}
dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
if !ok {
return fmt.Errorf("cannot find dimensions of %v for JSONArray", src)
}
if elementsLength == 0 {
*dst = JSONArray{Status: Present}
return nil
}
if len(dimensions) == 0 {
if originalSrc, ok := underlyingSliceType(src); ok {
return dst.Set(originalSrc)
}
return fmt.Errorf("cannot convert %v to JSONArray", src)
}
*dst = JSONArray{
Elements: make([]JSON, elementsLength),
Dimensions: dimensions,
Status: Present,
}
elementCount, err := dst.setRecursive(reflectedValue, 0, 0)
if err != nil {
// Maybe the target was one dimension too far, try again:
if len(dst.Dimensions) > 1 {
dst.Dimensions = dst.Dimensions[:len(dst.Dimensions)-1]
elementsLength = 0
for _, dim := range dst.Dimensions {
if elementsLength == 0 {
elementsLength = int(dim.Length)
} else {
elementsLength *= int(dim.Length)
}
}
dst.Elements = make([]JSON, elementsLength)
elementCount, err = dst.setRecursive(reflectedValue, 0, 0)
if err != nil {
return err
}
} else {
return err
}
}
if elementCount != len(dst.Elements) {
return fmt.Errorf("cannot convert %v to JSONArray, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
}
}
return nil
}
func (dst *JSONArray) setRecursive(value reflect.Value, index, dimension int) (int, error) {
switch value.Kind() {
case reflect.Array:
fallthrough
case reflect.Slice:
if len(dst.Dimensions) == dimension {
break
}
valueLen := value.Len()
if int32(valueLen) != dst.Dimensions[dimension].Length {
return 0, fmt.Errorf("multidimensional arrays must have array expressions with matching dimensions")
}
for i := 0; i < valueLen; i++ {
var err error
index, err = dst.setRecursive(value.Index(i), index, dimension+1)
if err != nil {
return 0, err
}
}
return index, nil
}
if !value.CanInterface() {
return 0, fmt.Errorf("cannot convert all values to JSONArray")
}
if err := dst.Elements[index].Set(value.Interface()); err != nil {
return 0, fmt.Errorf("%v in JSONArray", err)
}
index++
return index, nil
}
func (dst JSONArray) Get() interface{} {
switch dst.Status {
case Present:
return dst
case Null:
return nil
default:
return dst.Status
}
}
func (src *JSONArray) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
if len(src.Dimensions) <= 1 {
// Attempt to match to select common types:
switch v := dst.(type) {
case *[]string:
*v = make([]string, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[][]byte:
*v = make([][]byte, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]json.RawMessage:
*v = make([]json.RawMessage, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
}
}
// Try to convert to something AssignTo can use directly.
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
// Fallback to reflection if an optimised match was not found.
// The reflection is necessary for arrays and multidimensional slices,
// but it comes with a 20-50% performance penalty for large arrays/slices
value := reflect.ValueOf(dst)
if value.Kind() == reflect.Ptr {
value = value.Elem()
}
switch value.Kind() {
case reflect.Array, reflect.Slice:
default:
return fmt.Errorf("cannot assign %T to %T", src, dst)
}
if len(src.Elements) == 0 {
if value.Kind() == reflect.Slice {
value.Set(reflect.MakeSlice(value.Type(), 0, 0))
return nil
}
}
elementCount, err := src.assignToRecursive(value, 0, 0)
if err != nil {
return err
}
if elementCount != len(src.Elements) {
return fmt.Errorf("cannot assign %v, needed to assign %d elements, but only assigned %d", dst, len(src.Elements), elementCount)
}
return nil
case Null:
return NullAssignTo(dst)
}
return fmt.Errorf("cannot decode %#v into %T", src, dst)
}
func (src *JSONArray) assignToRecursive(value reflect.Value, index, dimension int) (int, error) {
switch kind := value.Kind(); kind {
case reflect.Array:
fallthrough
case reflect.Slice:
if len(src.Dimensions) == dimension {
break
}
length := int(src.Dimensions[dimension].Length)
if reflect.Array == kind {
typ := value.Type()
if typ.Len() != length {
return 0, fmt.Errorf("expected size %d array, but %s has size %d array", length, typ, typ.Len())
}
value.Set(reflect.New(typ).Elem())
} else {
value.Set(reflect.MakeSlice(value.Type(), length, length))
}
var err error
for i := 0; i < length; i++ {
index, err = src.assignToRecursive(value.Index(i), index, dimension+1)
if err != nil {
return 0, err
}
}
return index, nil
}
if len(src.Dimensions) != dimension {
return 0, fmt.Errorf("incorrect dimensions, expected %d, found %d", len(src.Dimensions), dimension)
}
if !value.CanAddr() {
return 0, fmt.Errorf("cannot assign all values from JSONArray")
}
addr := value.Addr()
if !addr.CanInterface() {
return 0, fmt.Errorf("cannot assign all values from JSONArray")
}
if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
return 0, err
}
index++
return index, nil
}
func (dst *JSONArray) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = JSONArray{Status: Null}
return nil
}
uta, err := ParseUntypedTextArray(string(src))
if err != nil {
return err
}
var elements []JSON
if len(uta.Elements) > 0 {
elements = make([]JSON, len(uta.Elements))
for i, s := range uta.Elements {
var elem JSON
var elemSrc []byte
if s != "NULL" || uta.Quoted[i] {
elemSrc = []byte(s)
}
err = elem.DecodeText(ci, elemSrc)
if err != nil {
return err
}
elements[i] = elem
}
}
*dst = JSONArray{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
return nil
}
func (dst *JSONArray) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = JSONArray{Status: Null}
return nil
}
var arrayHeader ArrayHeader
rp, err := arrayHeader.DecodeBinary(ci, src)
if err != nil {
return err
}
if len(arrayHeader.Dimensions) == 0 {
*dst = JSONArray{Dimensions: arrayHeader.Dimensions, Status: Present}
return nil
}
elementCount := arrayHeader.Dimensions[0].Length
for _, d := range arrayHeader.Dimensions[1:] {
elementCount *= d.Length
}
elements := make([]JSON, elementCount)
for i := range elements {
elemLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
rp += 4
var elemSrc []byte
if elemLen >= 0 {
elemSrc = src[rp : rp+elemLen]
rp += elemLen
}
err = elements[i].DecodeBinary(ci, elemSrc)
if err != nil {
return err
}
}
*dst = JSONArray{Elements: elements, Dimensions: arrayHeader.Dimensions, Status: Present}
return nil
}
func (src JSONArray) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
if len(src.Dimensions) == 0 {
return append(buf, '{', '}'), nil
}
buf = EncodeTextArrayDimensions(buf, src.Dimensions)
// dimElemCounts is the multiples of elements that each array lies on. For
// example, a single dimension array of length 4 would have a dimElemCounts of
// [4]. A multi-dimensional array of lengths [3,5,2] would have a
// dimElemCounts of [30,10,2]. This is used to simplify when to render a '{'
// or '}'.
dimElemCounts := make([]int, len(src.Dimensions))
dimElemCounts[len(src.Dimensions)-1] = int(src.Dimensions[len(src.Dimensions)-1].Length)
for i := len(src.Dimensions) - 2; i > -1; i-- {
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
}
inElemBuf := make([]byte, 0, 32)
for i, elem := range src.Elements {
if i > 0 {
buf = append(buf, ',')
}
for _, dec := range dimElemCounts {
if i%dec == 0 {
buf = append(buf, '{')
}
}
elemBuf, err := elem.EncodeText(ci, inElemBuf)
if err != nil {
return nil, err
}
if elemBuf == nil {
buf = append(buf, `NULL`...)
} else {
buf = append(buf, QuoteArrayElementIfNeeded(string(elemBuf))...)
}
for _, dec := range dimElemCounts {
if (i+1)%dec == 0 {
buf = append(buf, '}')
}
}
}
return buf, nil
}
func (src JSONArray) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
arrayHeader := ArrayHeader{
Dimensions: src.Dimensions,
}
if dt, ok := ci.DataTypeForName("json"); ok {
arrayHeader.ElementOID = int32(dt.OID)
} else {
return nil, fmt.Errorf("unable to find oid for type name %v", "json")
}
for i := range src.Elements {
if src.Elements[i].Status == Null {
arrayHeader.ContainsNull = true
break
}
}
buf = arrayHeader.EncodeBinary(ci, buf)
for i := range src.Elements {
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
elemBuf, err := src.Elements[i].EncodeBinary(ci, buf)
if err != nil {
return nil, err
}
if elemBuf != nil {
buf = elemBuf
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
}
return buf, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *JSONArray) Scan(src interface{}) error {
if src == nil {
return dst.DecodeText(nil, nil)
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src JSONArray) Value() (driver.Value, error) {
buf, err := src.EncodeText(nil, nil)
if err != nil {
return nil, err
}
if buf == nil {
return nil, nil
}
return string(buf), nil
}
-85
View File
@@ -1,85 +0,0 @@
package pgtype
import (
"database/sql/driver"
"fmt"
)
type JSONB JSON
func (dst *JSONB) Set(src interface{}) error {
return (*JSON)(dst).Set(src)
}
func (dst JSONB) Get() interface{} {
return (JSON)(dst).Get()
}
func (src *JSONB) AssignTo(dst interface{}) error {
return (*JSON)(src).AssignTo(dst)
}
func (JSONB) PreferredResultFormat() int16 {
return TextFormatCode
}
func (dst *JSONB) DecodeText(ci *ConnInfo, src []byte) error {
return (*JSON)(dst).DecodeText(ci, src)
}
func (dst *JSONB) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = JSONB{Status: Null}
return nil
}
if len(src) == 0 {
return fmt.Errorf("jsonb too short")
}
if src[0] != 1 {
return fmt.Errorf("unknown jsonb version number %d", src[0])
}
*dst = JSONB{Bytes: src[1:], Status: Present}
return nil
}
func (JSONB) PreferredParamFormat() int16 {
return TextFormatCode
}
func (src JSONB) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
return (JSON)(src).EncodeText(ci, buf)
}
func (src JSONB) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
buf = append(buf, 1)
return append(buf, src.Bytes...), nil
}
// Scan implements the database/sql Scanner interface.
func (dst *JSONB) Scan(src interface{}) error {
return (*JSON)(dst).Scan(src)
}
// Value implements the database/sql/driver Valuer interface.
func (src JSONB) Value() (driver.Value, error) {
return (JSON)(src).Value()
}
func (src JSONB) MarshalJSON() ([]byte, error) {
return (JSON)(src).MarshalJSON()
}
func (dst *JSONB) UnmarshalJSON(b []byte) error {
return (*JSON)(dst).UnmarshalJSON(b)
}
-546
View File
@@ -1,546 +0,0 @@
// Code generated by erb. DO NOT EDIT.
package pgtype
import (
"database/sql/driver"
"encoding/binary"
"encoding/json"
"fmt"
"reflect"
"github.com/jackc/pgio"
)
type JSONBArray struct {
Elements []JSONB
Dimensions []ArrayDimension
Status Status
}
func (dst *JSONBArray) Set(src interface{}) error {
// untyped nil and typed nil interfaces are different
if src == nil {
*dst = JSONBArray{Status: Null}
return nil
}
if value, ok := src.(interface{ Get() interface{} }); ok {
value2 := value.Get()
if value2 != value {
return dst.Set(value2)
}
}
// Attempt to match to select common types:
switch value := src.(type) {
case []string:
if value == nil {
*dst = JSONBArray{Status: Null}
} else if len(value) == 0 {
*dst = JSONBArray{Status: Present}
} else {
elements := make([]JSONB, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = JSONBArray{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case [][]byte:
if value == nil {
*dst = JSONBArray{Status: Null}
} else if len(value) == 0 {
*dst = JSONBArray{Status: Present}
} else {
elements := make([]JSONB, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = JSONBArray{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []json.RawMessage:
if value == nil {
*dst = JSONBArray{Status: Null}
} else if len(value) == 0 {
*dst = JSONBArray{Status: Present}
} else {
elements := make([]JSONB, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = JSONBArray{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []JSONB:
if value == nil {
*dst = JSONBArray{Status: Null}
} else if len(value) == 0 {
*dst = JSONBArray{Status: Present}
} else {
*dst = JSONBArray{
Elements: value,
Dimensions: []ArrayDimension{{Length: int32(len(value)), LowerBound: 1}},
Status: Present,
}
}
default:
// Fallback to reflection if an optimised match was not found.
// The reflection is necessary for arrays and multidimensional slices,
// but it comes with a 20-50% performance penalty for large arrays/slices
reflectedValue := reflect.ValueOf(src)
if !reflectedValue.IsValid() || reflectedValue.IsZero() {
*dst = JSONBArray{Status: Null}
return nil
}
dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
if !ok {
return fmt.Errorf("cannot find dimensions of %v for JSONBArray", src)
}
if elementsLength == 0 {
*dst = JSONBArray{Status: Present}
return nil
}
if len(dimensions) == 0 {
if originalSrc, ok := underlyingSliceType(src); ok {
return dst.Set(originalSrc)
}
return fmt.Errorf("cannot convert %v to JSONBArray", src)
}
*dst = JSONBArray{
Elements: make([]JSONB, elementsLength),
Dimensions: dimensions,
Status: Present,
}
elementCount, err := dst.setRecursive(reflectedValue, 0, 0)
if err != nil {
// Maybe the target was one dimension too far, try again:
if len(dst.Dimensions) > 1 {
dst.Dimensions = dst.Dimensions[:len(dst.Dimensions)-1]
elementsLength = 0
for _, dim := range dst.Dimensions {
if elementsLength == 0 {
elementsLength = int(dim.Length)
} else {
elementsLength *= int(dim.Length)
}
}
dst.Elements = make([]JSONB, elementsLength)
elementCount, err = dst.setRecursive(reflectedValue, 0, 0)
if err != nil {
return err
}
} else {
return err
}
}
if elementCount != len(dst.Elements) {
return fmt.Errorf("cannot convert %v to JSONBArray, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
}
}
return nil
}
func (dst *JSONBArray) setRecursive(value reflect.Value, index, dimension int) (int, error) {
switch value.Kind() {
case reflect.Array:
fallthrough
case reflect.Slice:
if len(dst.Dimensions) == dimension {
break
}
valueLen := value.Len()
if int32(valueLen) != dst.Dimensions[dimension].Length {
return 0, fmt.Errorf("multidimensional arrays must have array expressions with matching dimensions")
}
for i := 0; i < valueLen; i++ {
var err error
index, err = dst.setRecursive(value.Index(i), index, dimension+1)
if err != nil {
return 0, err
}
}
return index, nil
}
if !value.CanInterface() {
return 0, fmt.Errorf("cannot convert all values to JSONBArray")
}
if err := dst.Elements[index].Set(value.Interface()); err != nil {
return 0, fmt.Errorf("%v in JSONBArray", err)
}
index++
return index, nil
}
func (dst JSONBArray) Get() interface{} {
switch dst.Status {
case Present:
return dst
case Null:
return nil
default:
return dst.Status
}
}
func (src *JSONBArray) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
if len(src.Dimensions) <= 1 {
// Attempt to match to select common types:
switch v := dst.(type) {
case *[]string:
*v = make([]string, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[][]byte:
*v = make([][]byte, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]json.RawMessage:
*v = make([]json.RawMessage, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
}
}
// Try to convert to something AssignTo can use directly.
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
// Fallback to reflection if an optimised match was not found.
// The reflection is necessary for arrays and multidimensional slices,
// but it comes with a 20-50% performance penalty for large arrays/slices
value := reflect.ValueOf(dst)
if value.Kind() == reflect.Ptr {
value = value.Elem()
}
switch value.Kind() {
case reflect.Array, reflect.Slice:
default:
return fmt.Errorf("cannot assign %T to %T", src, dst)
}
if len(src.Elements) == 0 {
if value.Kind() == reflect.Slice {
value.Set(reflect.MakeSlice(value.Type(), 0, 0))
return nil
}
}
elementCount, err := src.assignToRecursive(value, 0, 0)
if err != nil {
return err
}
if elementCount != len(src.Elements) {
return fmt.Errorf("cannot assign %v, needed to assign %d elements, but only assigned %d", dst, len(src.Elements), elementCount)
}
return nil
case Null:
return NullAssignTo(dst)
}
return fmt.Errorf("cannot decode %#v into %T", src, dst)
}
func (src *JSONBArray) assignToRecursive(value reflect.Value, index, dimension int) (int, error) {
switch kind := value.Kind(); kind {
case reflect.Array:
fallthrough
case reflect.Slice:
if len(src.Dimensions) == dimension {
break
}
length := int(src.Dimensions[dimension].Length)
if reflect.Array == kind {
typ := value.Type()
if typ.Len() != length {
return 0, fmt.Errorf("expected size %d array, but %s has size %d array", length, typ, typ.Len())
}
value.Set(reflect.New(typ).Elem())
} else {
value.Set(reflect.MakeSlice(value.Type(), length, length))
}
var err error
for i := 0; i < length; i++ {
index, err = src.assignToRecursive(value.Index(i), index, dimension+1)
if err != nil {
return 0, err
}
}
return index, nil
}
if len(src.Dimensions) != dimension {
return 0, fmt.Errorf("incorrect dimensions, expected %d, found %d", len(src.Dimensions), dimension)
}
if !value.CanAddr() {
return 0, fmt.Errorf("cannot assign all values from JSONBArray")
}
addr := value.Addr()
if !addr.CanInterface() {
return 0, fmt.Errorf("cannot assign all values from JSONBArray")
}
if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
return 0, err
}
index++
return index, nil
}
func (dst *JSONBArray) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = JSONBArray{Status: Null}
return nil
}
uta, err := ParseUntypedTextArray(string(src))
if err != nil {
return err
}
var elements []JSONB
if len(uta.Elements) > 0 {
elements = make([]JSONB, len(uta.Elements))
for i, s := range uta.Elements {
var elem JSONB
var elemSrc []byte
if s != "NULL" || uta.Quoted[i] {
elemSrc = []byte(s)
}
err = elem.DecodeText(ci, elemSrc)
if err != nil {
return err
}
elements[i] = elem
}
}
*dst = JSONBArray{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
return nil
}
func (dst *JSONBArray) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = JSONBArray{Status: Null}
return nil
}
var arrayHeader ArrayHeader
rp, err := arrayHeader.DecodeBinary(ci, src)
if err != nil {
return err
}
if len(arrayHeader.Dimensions) == 0 {
*dst = JSONBArray{Dimensions: arrayHeader.Dimensions, Status: Present}
return nil
}
elementCount := arrayHeader.Dimensions[0].Length
for _, d := range arrayHeader.Dimensions[1:] {
elementCount *= d.Length
}
elements := make([]JSONB, elementCount)
for i := range elements {
elemLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
rp += 4
var elemSrc []byte
if elemLen >= 0 {
elemSrc = src[rp : rp+elemLen]
rp += elemLen
}
err = elements[i].DecodeBinary(ci, elemSrc)
if err != nil {
return err
}
}
*dst = JSONBArray{Elements: elements, Dimensions: arrayHeader.Dimensions, Status: Present}
return nil
}
func (src JSONBArray) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
if len(src.Dimensions) == 0 {
return append(buf, '{', '}'), nil
}
buf = EncodeTextArrayDimensions(buf, src.Dimensions)
// dimElemCounts is the multiples of elements that each array lies on. For
// example, a single dimension array of length 4 would have a dimElemCounts of
// [4]. A multi-dimensional array of lengths [3,5,2] would have a
// dimElemCounts of [30,10,2]. This is used to simplify when to render a '{'
// or '}'.
dimElemCounts := make([]int, len(src.Dimensions))
dimElemCounts[len(src.Dimensions)-1] = int(src.Dimensions[len(src.Dimensions)-1].Length)
for i := len(src.Dimensions) - 2; i > -1; i-- {
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
}
inElemBuf := make([]byte, 0, 32)
for i, elem := range src.Elements {
if i > 0 {
buf = append(buf, ',')
}
for _, dec := range dimElemCounts {
if i%dec == 0 {
buf = append(buf, '{')
}
}
elemBuf, err := elem.EncodeText(ci, inElemBuf)
if err != nil {
return nil, err
}
if elemBuf == nil {
buf = append(buf, `NULL`...)
} else {
buf = append(buf, QuoteArrayElementIfNeeded(string(elemBuf))...)
}
for _, dec := range dimElemCounts {
if (i+1)%dec == 0 {
buf = append(buf, '}')
}
}
}
return buf, nil
}
func (src JSONBArray) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
arrayHeader := ArrayHeader{
Dimensions: src.Dimensions,
}
if dt, ok := ci.DataTypeForName("jsonb"); ok {
arrayHeader.ElementOID = int32(dt.OID)
} else {
return nil, fmt.Errorf("unable to find oid for type name %v", "jsonb")
}
for i := range src.Elements {
if src.Elements[i].Status == Null {
arrayHeader.ContainsNull = true
break
}
}
buf = arrayHeader.EncodeBinary(ci, buf)
for i := range src.Elements {
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
elemBuf, err := src.Elements[i].EncodeBinary(ci, buf)
if err != nil {
return nil, err
}
if elemBuf != nil {
buf = elemBuf
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
}
return buf, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *JSONBArray) Scan(src interface{}) error {
if src == nil {
return dst.DecodeText(nil, nil)
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src JSONBArray) Value() (driver.Value, error) {
buf, err := src.EncodeText(nil, nil)
if err != nil {
return nil, err
}
if buf == nil {
return nil, nil
}
return string(buf), nil
}
-148
View File
@@ -1,148 +0,0 @@
package pgtype
import (
"database/sql/driver"
"encoding/binary"
"fmt"
"math"
"strconv"
"strings"
"github.com/jackc/pgio"
)
type Line struct {
A, B, C float64
Status Status
}
func (dst *Line) Set(src interface{}) error {
return fmt.Errorf("cannot convert %v to Line", src)
}
func (dst Line) Get() interface{} {
switch dst.Status {
case Present:
return dst
case Null:
return nil
default:
return dst.Status
}
}
func (src *Line) AssignTo(dst interface{}) error {
return fmt.Errorf("cannot assign %v to %T", src, dst)
}
func (dst *Line) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Line{Status: Null}
return nil
}
if len(src) < 7 {
return fmt.Errorf("invalid length for Line: %v", len(src))
}
parts := strings.SplitN(string(src[1:len(src)-1]), ",", 3)
if len(parts) < 3 {
return fmt.Errorf("invalid format for line")
}
a, err := strconv.ParseFloat(parts[0], 64)
if err != nil {
return err
}
b, err := strconv.ParseFloat(parts[1], 64)
if err != nil {
return err
}
c, err := strconv.ParseFloat(parts[2], 64)
if err != nil {
return err
}
*dst = Line{A: a, B: b, C: c, Status: Present}
return nil
}
func (dst *Line) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Line{Status: Null}
return nil
}
if len(src) != 24 {
return fmt.Errorf("invalid length for Line: %v", len(src))
}
a := binary.BigEndian.Uint64(src)
b := binary.BigEndian.Uint64(src[8:])
c := binary.BigEndian.Uint64(src[16:])
*dst = Line{
A: math.Float64frombits(a),
B: math.Float64frombits(b),
C: math.Float64frombits(c),
Status: Present,
}
return nil
}
func (src Line) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
buf = append(buf, fmt.Sprintf(`{%s,%s,%s}`,
strconv.FormatFloat(src.A, 'f', -1, 64),
strconv.FormatFloat(src.B, 'f', -1, 64),
strconv.FormatFloat(src.C, 'f', -1, 64),
)...)
return buf, nil
}
func (src Line) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
buf = pgio.AppendUint64(buf, math.Float64bits(src.A))
buf = pgio.AppendUint64(buf, math.Float64bits(src.B))
buf = pgio.AppendUint64(buf, math.Float64bits(src.C))
return buf, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *Line) Scan(src interface{}) error {
if src == nil {
*dst = Line{Status: Null}
return nil
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src Line) Value() (driver.Value, error) {
return EncodeValueText(src)
}
-165
View File
@@ -1,165 +0,0 @@
package pgtype
import (
"database/sql/driver"
"encoding/binary"
"fmt"
"math"
"strconv"
"strings"
"github.com/jackc/pgio"
)
type Lseg struct {
P [2]Vec2
Status Status
}
func (dst *Lseg) Set(src interface{}) error {
return fmt.Errorf("cannot convert %v to Lseg", src)
}
func (dst Lseg) Get() interface{} {
switch dst.Status {
case Present:
return dst
case Null:
return nil
default:
return dst.Status
}
}
func (src *Lseg) AssignTo(dst interface{}) error {
return fmt.Errorf("cannot assign %v to %T", src, dst)
}
func (dst *Lseg) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Lseg{Status: Null}
return nil
}
if len(src) < 11 {
return fmt.Errorf("invalid length for Lseg: %v", len(src))
}
str := string(src[2:])
var end int
end = strings.IndexByte(str, ',')
x1, err := strconv.ParseFloat(str[:end], 64)
if err != nil {
return err
}
str = str[end+1:]
end = strings.IndexByte(str, ')')
y1, err := strconv.ParseFloat(str[:end], 64)
if err != nil {
return err
}
str = str[end+3:]
end = strings.IndexByte(str, ',')
x2, err := strconv.ParseFloat(str[:end], 64)
if err != nil {
return err
}
str = str[end+1 : len(str)-2]
y2, err := strconv.ParseFloat(str, 64)
if err != nil {
return err
}
*dst = Lseg{P: [2]Vec2{{x1, y1}, {x2, y2}}, Status: Present}
return nil
}
func (dst *Lseg) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Lseg{Status: Null}
return nil
}
if len(src) != 32 {
return fmt.Errorf("invalid length for Lseg: %v", len(src))
}
x1 := binary.BigEndian.Uint64(src)
y1 := binary.BigEndian.Uint64(src[8:])
x2 := binary.BigEndian.Uint64(src[16:])
y2 := binary.BigEndian.Uint64(src[24:])
*dst = Lseg{
P: [2]Vec2{
{math.Float64frombits(x1), math.Float64frombits(y1)},
{math.Float64frombits(x2), math.Float64frombits(y2)},
},
Status: Present,
}
return nil
}
func (src Lseg) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
buf = append(buf, fmt.Sprintf(`(%s,%s),(%s,%s)`,
strconv.FormatFloat(src.P[0].X, 'f', -1, 64),
strconv.FormatFloat(src.P[0].Y, 'f', -1, 64),
strconv.FormatFloat(src.P[1].X, 'f', -1, 64),
strconv.FormatFloat(src.P[1].Y, 'f', -1, 64),
)...)
return buf, nil
}
func (src Lseg) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
buf = pgio.AppendUint64(buf, math.Float64bits(src.P[0].X))
buf = pgio.AppendUint64(buf, math.Float64bits(src.P[0].Y))
buf = pgio.AppendUint64(buf, math.Float64bits(src.P[1].X))
buf = pgio.AppendUint64(buf, math.Float64bits(src.P[1].Y))
return buf, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *Lseg) Scan(src interface{}) error {
if src == nil {
*dst = Lseg{Status: Null}
return nil
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src Lseg) Value() (driver.Value, error) {
return EncodeValueText(src)
}
-173
View File
@@ -1,173 +0,0 @@
package pgtype
import (
"database/sql/driver"
"fmt"
"net"
)
type Macaddr struct {
Addr net.HardwareAddr
Status Status
}
func (dst *Macaddr) Set(src interface{}) error {
if src == nil {
*dst = Macaddr{Status: Null}
return nil
}
if value, ok := src.(interface{ Get() interface{} }); ok {
value2 := value.Get()
if value2 != value {
return dst.Set(value2)
}
}
switch value := src.(type) {
case net.HardwareAddr:
addr := make(net.HardwareAddr, len(value))
copy(addr, value)
*dst = Macaddr{Addr: addr, Status: Present}
case string:
addr, err := net.ParseMAC(value)
if err != nil {
return err
}
*dst = Macaddr{Addr: addr, Status: Present}
case *net.HardwareAddr:
if value == nil {
*dst = Macaddr{Status: Null}
} else {
return dst.Set(*value)
}
case *string:
if value == nil {
*dst = Macaddr{Status: Null}
} else {
return dst.Set(*value)
}
default:
if originalSrc, ok := underlyingPtrType(src); ok {
return dst.Set(originalSrc)
}
return fmt.Errorf("cannot convert %v to Macaddr", value)
}
return nil
}
func (dst Macaddr) Get() interface{} {
switch dst.Status {
case Present:
return dst.Addr
case Null:
return nil
default:
return dst.Status
}
}
func (src *Macaddr) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
switch v := dst.(type) {
case *net.HardwareAddr:
*v = make(net.HardwareAddr, len(src.Addr))
copy(*v, src.Addr)
return nil
case *string:
*v = src.Addr.String()
return nil
default:
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
return fmt.Errorf("unable to assign to %T", dst)
}
case Null:
return NullAssignTo(dst)
}
return fmt.Errorf("cannot decode %#v into %T", src, dst)
}
func (dst *Macaddr) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Macaddr{Status: Null}
return nil
}
addr, err := net.ParseMAC(string(src))
if err != nil {
return err
}
*dst = Macaddr{Addr: addr, Status: Present}
return nil
}
func (dst *Macaddr) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Macaddr{Status: Null}
return nil
}
if len(src) != 6 {
return fmt.Errorf("Received an invalid size for a macaddr: %d", len(src))
}
addr := make(net.HardwareAddr, 6)
copy(addr, src)
*dst = Macaddr{Addr: addr, Status: Present}
return nil
}
func (src Macaddr) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
return append(buf, src.Addr.String()...), nil
}
// EncodeBinary encodes src into w.
func (src Macaddr) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
return append(buf, src.Addr...), nil
}
// Scan implements the database/sql Scanner interface.
func (dst *Macaddr) Scan(src interface{}) error {
if src == nil {
*dst = Macaddr{Status: Null}
return nil
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src Macaddr) Value() (driver.Value, error) {
return EncodeValueText(src)
}
-518
View File
@@ -1,518 +0,0 @@
// Code generated by erb. DO NOT EDIT.
package pgtype
import (
"database/sql/driver"
"encoding/binary"
"fmt"
"net"
"reflect"
"github.com/jackc/pgio"
)
type MacaddrArray struct {
Elements []Macaddr
Dimensions []ArrayDimension
Status Status
}
func (dst *MacaddrArray) Set(src interface{}) error {
// untyped nil and typed nil interfaces are different
if src == nil {
*dst = MacaddrArray{Status: Null}
return nil
}
if value, ok := src.(interface{ Get() interface{} }); ok {
value2 := value.Get()
if value2 != value {
return dst.Set(value2)
}
}
// Attempt to match to select common types:
switch value := src.(type) {
case []net.HardwareAddr:
if value == nil {
*dst = MacaddrArray{Status: Null}
} else if len(value) == 0 {
*dst = MacaddrArray{Status: Present}
} else {
elements := make([]Macaddr, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = MacaddrArray{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []*net.HardwareAddr:
if value == nil {
*dst = MacaddrArray{Status: Null}
} else if len(value) == 0 {
*dst = MacaddrArray{Status: Present}
} else {
elements := make([]Macaddr, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = MacaddrArray{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []Macaddr:
if value == nil {
*dst = MacaddrArray{Status: Null}
} else if len(value) == 0 {
*dst = MacaddrArray{Status: Present}
} else {
*dst = MacaddrArray{
Elements: value,
Dimensions: []ArrayDimension{{Length: int32(len(value)), LowerBound: 1}},
Status: Present,
}
}
default:
// Fallback to reflection if an optimised match was not found.
// The reflection is necessary for arrays and multidimensional slices,
// but it comes with a 20-50% performance penalty for large arrays/slices
reflectedValue := reflect.ValueOf(src)
if !reflectedValue.IsValid() || reflectedValue.IsZero() {
*dst = MacaddrArray{Status: Null}
return nil
}
dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
if !ok {
return fmt.Errorf("cannot find dimensions of %v for MacaddrArray", src)
}
if elementsLength == 0 {
*dst = MacaddrArray{Status: Present}
return nil
}
if len(dimensions) == 0 {
if originalSrc, ok := underlyingSliceType(src); ok {
return dst.Set(originalSrc)
}
return fmt.Errorf("cannot convert %v to MacaddrArray", src)
}
*dst = MacaddrArray{
Elements: make([]Macaddr, elementsLength),
Dimensions: dimensions,
Status: Present,
}
elementCount, err := dst.setRecursive(reflectedValue, 0, 0)
if err != nil {
// Maybe the target was one dimension too far, try again:
if len(dst.Dimensions) > 1 {
dst.Dimensions = dst.Dimensions[:len(dst.Dimensions)-1]
elementsLength = 0
for _, dim := range dst.Dimensions {
if elementsLength == 0 {
elementsLength = int(dim.Length)
} else {
elementsLength *= int(dim.Length)
}
}
dst.Elements = make([]Macaddr, elementsLength)
elementCount, err = dst.setRecursive(reflectedValue, 0, 0)
if err != nil {
return err
}
} else {
return err
}
}
if elementCount != len(dst.Elements) {
return fmt.Errorf("cannot convert %v to MacaddrArray, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
}
}
return nil
}
func (dst *MacaddrArray) setRecursive(value reflect.Value, index, dimension int) (int, error) {
switch value.Kind() {
case reflect.Array:
fallthrough
case reflect.Slice:
if len(dst.Dimensions) == dimension {
break
}
valueLen := value.Len()
if int32(valueLen) != dst.Dimensions[dimension].Length {
return 0, fmt.Errorf("multidimensional arrays must have array expressions with matching dimensions")
}
for i := 0; i < valueLen; i++ {
var err error
index, err = dst.setRecursive(value.Index(i), index, dimension+1)
if err != nil {
return 0, err
}
}
return index, nil
}
if !value.CanInterface() {
return 0, fmt.Errorf("cannot convert all values to MacaddrArray")
}
if err := dst.Elements[index].Set(value.Interface()); err != nil {
return 0, fmt.Errorf("%v in MacaddrArray", err)
}
index++
return index, nil
}
func (dst MacaddrArray) Get() interface{} {
switch dst.Status {
case Present:
return dst
case Null:
return nil
default:
return dst.Status
}
}
func (src *MacaddrArray) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
if len(src.Dimensions) <= 1 {
// Attempt to match to select common types:
switch v := dst.(type) {
case *[]net.HardwareAddr:
*v = make([]net.HardwareAddr, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]*net.HardwareAddr:
*v = make([]*net.HardwareAddr, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
}
}
// Try to convert to something AssignTo can use directly.
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
// Fallback to reflection if an optimised match was not found.
// The reflection is necessary for arrays and multidimensional slices,
// but it comes with a 20-50% performance penalty for large arrays/slices
value := reflect.ValueOf(dst)
if value.Kind() == reflect.Ptr {
value = value.Elem()
}
switch value.Kind() {
case reflect.Array, reflect.Slice:
default:
return fmt.Errorf("cannot assign %T to %T", src, dst)
}
if len(src.Elements) == 0 {
if value.Kind() == reflect.Slice {
value.Set(reflect.MakeSlice(value.Type(), 0, 0))
return nil
}
}
elementCount, err := src.assignToRecursive(value, 0, 0)
if err != nil {
return err
}
if elementCount != len(src.Elements) {
return fmt.Errorf("cannot assign %v, needed to assign %d elements, but only assigned %d", dst, len(src.Elements), elementCount)
}
return nil
case Null:
return NullAssignTo(dst)
}
return fmt.Errorf("cannot decode %#v into %T", src, dst)
}
func (src *MacaddrArray) assignToRecursive(value reflect.Value, index, dimension int) (int, error) {
switch kind := value.Kind(); kind {
case reflect.Array:
fallthrough
case reflect.Slice:
if len(src.Dimensions) == dimension {
break
}
length := int(src.Dimensions[dimension].Length)
if reflect.Array == kind {
typ := value.Type()
if typ.Len() != length {
return 0, fmt.Errorf("expected size %d array, but %s has size %d array", length, typ, typ.Len())
}
value.Set(reflect.New(typ).Elem())
} else {
value.Set(reflect.MakeSlice(value.Type(), length, length))
}
var err error
for i := 0; i < length; i++ {
index, err = src.assignToRecursive(value.Index(i), index, dimension+1)
if err != nil {
return 0, err
}
}
return index, nil
}
if len(src.Dimensions) != dimension {
return 0, fmt.Errorf("incorrect dimensions, expected %d, found %d", len(src.Dimensions), dimension)
}
if !value.CanAddr() {
return 0, fmt.Errorf("cannot assign all values from MacaddrArray")
}
addr := value.Addr()
if !addr.CanInterface() {
return 0, fmt.Errorf("cannot assign all values from MacaddrArray")
}
if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
return 0, err
}
index++
return index, nil
}
func (dst *MacaddrArray) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = MacaddrArray{Status: Null}
return nil
}
uta, err := ParseUntypedTextArray(string(src))
if err != nil {
return err
}
var elements []Macaddr
if len(uta.Elements) > 0 {
elements = make([]Macaddr, len(uta.Elements))
for i, s := range uta.Elements {
var elem Macaddr
var elemSrc []byte
if s != "NULL" || uta.Quoted[i] {
elemSrc = []byte(s)
}
err = elem.DecodeText(ci, elemSrc)
if err != nil {
return err
}
elements[i] = elem
}
}
*dst = MacaddrArray{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
return nil
}
func (dst *MacaddrArray) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = MacaddrArray{Status: Null}
return nil
}
var arrayHeader ArrayHeader
rp, err := arrayHeader.DecodeBinary(ci, src)
if err != nil {
return err
}
if len(arrayHeader.Dimensions) == 0 {
*dst = MacaddrArray{Dimensions: arrayHeader.Dimensions, Status: Present}
return nil
}
elementCount := arrayHeader.Dimensions[0].Length
for _, d := range arrayHeader.Dimensions[1:] {
elementCount *= d.Length
}
elements := make([]Macaddr, elementCount)
for i := range elements {
elemLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
rp += 4
var elemSrc []byte
if elemLen >= 0 {
elemSrc = src[rp : rp+elemLen]
rp += elemLen
}
err = elements[i].DecodeBinary(ci, elemSrc)
if err != nil {
return err
}
}
*dst = MacaddrArray{Elements: elements, Dimensions: arrayHeader.Dimensions, Status: Present}
return nil
}
func (src MacaddrArray) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
if len(src.Dimensions) == 0 {
return append(buf, '{', '}'), nil
}
buf = EncodeTextArrayDimensions(buf, src.Dimensions)
// dimElemCounts is the multiples of elements that each array lies on. For
// example, a single dimension array of length 4 would have a dimElemCounts of
// [4]. A multi-dimensional array of lengths [3,5,2] would have a
// dimElemCounts of [30,10,2]. This is used to simplify when to render a '{'
// or '}'.
dimElemCounts := make([]int, len(src.Dimensions))
dimElemCounts[len(src.Dimensions)-1] = int(src.Dimensions[len(src.Dimensions)-1].Length)
for i := len(src.Dimensions) - 2; i > -1; i-- {
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
}
inElemBuf := make([]byte, 0, 32)
for i, elem := range src.Elements {
if i > 0 {
buf = append(buf, ',')
}
for _, dec := range dimElemCounts {
if i%dec == 0 {
buf = append(buf, '{')
}
}
elemBuf, err := elem.EncodeText(ci, inElemBuf)
if err != nil {
return nil, err
}
if elemBuf == nil {
buf = append(buf, `NULL`...)
} else {
buf = append(buf, QuoteArrayElementIfNeeded(string(elemBuf))...)
}
for _, dec := range dimElemCounts {
if (i+1)%dec == 0 {
buf = append(buf, '}')
}
}
}
return buf, nil
}
func (src MacaddrArray) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
arrayHeader := ArrayHeader{
Dimensions: src.Dimensions,
}
if dt, ok := ci.DataTypeForName("macaddr"); ok {
arrayHeader.ElementOID = int32(dt.OID)
} else {
return nil, fmt.Errorf("unable to find oid for type name %v", "macaddr")
}
for i := range src.Elements {
if src.Elements[i].Status == Null {
arrayHeader.ContainsNull = true
break
}
}
buf = arrayHeader.EncodeBinary(ci, buf)
for i := range src.Elements {
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
elemBuf, err := src.Elements[i].EncodeBinary(ci, buf)
if err != nil {
return nil, err
}
if elemBuf != nil {
buf = elemBuf
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
}
return buf, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *MacaddrArray) Scan(src interface{}) error {
if src == nil {
return dst.DecodeText(nil, nil)
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src MacaddrArray) Value() (driver.Value, error) {
buf, err := src.EncodeText(nil, nil)
if err != nil {
return nil, err
}
if buf == nil {
return nil, nil
}
return string(buf), nil
}
-83
View File
@@ -1,83 +0,0 @@
package pgtype
import (
"bytes"
"fmt"
)
type UntypedTextMultirange struct {
Elements []string
}
func ParseUntypedTextMultirange(src string) (*UntypedTextMultirange, error) {
utmr := &UntypedTextMultirange{}
utmr.Elements = make([]string, 0)
buf := bytes.NewBufferString(src)
skipWhitespace(buf)
r, _, err := buf.ReadRune()
if err != nil {
return nil, fmt.Errorf("invalid array: %v", err)
}
if r != '{' {
return nil, fmt.Errorf("invalid multirange, expected '{': %v", err)
}
parseValueLoop:
for {
r, _, err = buf.ReadRune()
if err != nil {
return nil, fmt.Errorf("invalid multirange: %v", err)
}
switch r {
case ',': // skip range separator
case '}':
break parseValueLoop
default:
buf.UnreadRune()
value, err := parseRange(buf)
if err != nil {
return nil, fmt.Errorf("invalid multirange value: %v", err)
}
utmr.Elements = append(utmr.Elements, value)
}
}
skipWhitespace(buf)
if buf.Len() > 0 {
return nil, fmt.Errorf("unexpected trailing data: %v", buf.String())
}
return utmr, nil
}
func parseRange(buf *bytes.Buffer) (string, error) {
s := &bytes.Buffer{}
boundSepRead := false
for {
r, _, err := buf.ReadRune()
if err != nil {
return "", err
}
switch r {
case ',', '}':
if r == ',' && !boundSepRead {
boundSepRead = true
break
}
buf.UnreadRune()
return s.String(), nil
}
s.WriteRune(r)
}
}
-58
View File
@@ -1,58 +0,0 @@
package pgtype
import (
"database/sql/driver"
)
// Name is a type used for PostgreSQL's special 63-byte
// name data type, used for identifiers like table names.
// The pg_class.relname column is a good example of where the
// name data type is used.
//
// Note that the underlying Go data type of pgx.Name is string,
// so there is no way to enforce the 63-byte length. Inputting
// a longer name into PostgreSQL will result in silent truncation
// to 63 bytes.
//
// Also, if you have custom-compiled PostgreSQL and set
// NAMEDATALEN to a different value, obviously that number of
// bytes applies, rather than the default 63.
type Name Text
func (dst *Name) Set(src interface{}) error {
return (*Text)(dst).Set(src)
}
func (dst Name) Get() interface{} {
return (Text)(dst).Get()
}
func (src *Name) AssignTo(dst interface{}) error {
return (*Text)(src).AssignTo(dst)
}
func (dst *Name) DecodeText(ci *ConnInfo, src []byte) error {
return (*Text)(dst).DecodeText(ci, src)
}
func (dst *Name) DecodeBinary(ci *ConnInfo, src []byte) error {
return (*Text)(dst).DecodeBinary(ci, src)
}
func (src Name) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
return (Text)(src).EncodeText(ci, buf)
}
func (src Name) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
return (Text)(src).EncodeBinary(ci, buf)
}
// Scan implements the database/sql Scanner interface.
func (dst *Name) Scan(src interface{}) error {
return (*Text)(dst).Scan(src)
}
// Value implements the database/sql/driver Valuer interface.
func (src Name) Value() (driver.Value, error) {
return (Text)(src).Value()
}
-239
View File
@@ -1,239 +0,0 @@
package pgtype
import (
"database/sql/driver"
"encoding/binary"
"fmt"
"github.com/jackc/pgio"
)
type Nummultirange struct {
Ranges []Numrange
Status Status
}
func (dst *Nummultirange) Set(src interface{}) error {
//untyped nil and typed nil interfaces are different
if src == nil {
*dst = Nummultirange{Status: Null}
return nil
}
switch value := src.(type) {
case Nummultirange:
*dst = value
case *Nummultirange:
*dst = *value
case string:
return dst.DecodeText(nil, []byte(value))
case []Numrange:
if value == nil {
*dst = Nummultirange{Status: Null}
} else if len(value) == 0 {
*dst = Nummultirange{Status: Present}
} else {
elements := make([]Numrange, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Nummultirange{
Ranges: elements,
Status: Present,
}
}
case []*Numrange:
if value == nil {
*dst = Nummultirange{Status: Null}
} else if len(value) == 0 {
*dst = Nummultirange{Status: Present}
} else {
elements := make([]Numrange, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = Nummultirange{
Ranges: elements,
Status: Present,
}
}
default:
return fmt.Errorf("cannot convert %v to Nummultirange", src)
}
return nil
}
func (dst Nummultirange) Get() interface{} {
switch dst.Status {
case Present:
return dst
case Null:
return nil
default:
return dst.Status
}
}
func (src *Nummultirange) AssignTo(dst interface{}) error {
return fmt.Errorf("cannot assign %v to %T", src, dst)
}
func (dst *Nummultirange) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Nummultirange{Status: Null}
return nil
}
utmr, err := ParseUntypedTextMultirange(string(src))
if err != nil {
return err
}
var elements []Numrange
if len(utmr.Elements) > 0 {
elements = make([]Numrange, len(utmr.Elements))
for i, s := range utmr.Elements {
var elem Numrange
elemSrc := []byte(s)
err = elem.DecodeText(ci, elemSrc)
if err != nil {
return err
}
elements[i] = elem
}
}
*dst = Nummultirange{Ranges: elements, Status: Present}
return nil
}
func (dst *Nummultirange) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Nummultirange{Status: Null}
return nil
}
rp := 0
numElems := int(binary.BigEndian.Uint32(src[rp:]))
rp += 4
if numElems == 0 {
*dst = Nummultirange{Status: Present}
return nil
}
elements := make([]Numrange, numElems)
for i := range elements {
elemLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
rp += 4
var elemSrc []byte
if elemLen >= 0 {
elemSrc = src[rp : rp+elemLen]
rp += elemLen
}
err := elements[i].DecodeBinary(ci, elemSrc)
if err != nil {
return err
}
}
*dst = Nummultirange{Ranges: elements, Status: Present}
return nil
}
func (src Nummultirange) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
buf = append(buf, '{')
inElemBuf := make([]byte, 0, 32)
for i, elem := range src.Ranges {
if i > 0 {
buf = append(buf, ',')
}
elemBuf, err := elem.EncodeText(ci, inElemBuf)
if err != nil {
return nil, err
}
if elemBuf == nil {
return nil, fmt.Errorf("multi-range does not allow null range")
} else {
buf = append(buf, string(elemBuf)...)
}
}
buf = append(buf, '}')
return buf, nil
}
func (src Nummultirange) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
buf = pgio.AppendInt32(buf, int32(len(src.Ranges)))
for i := range src.Ranges {
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
elemBuf, err := src.Ranges[i].EncodeBinary(ci, buf)
if err != nil {
return nil, err
}
if elemBuf != nil {
buf = elemBuf
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
}
return buf, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *Nummultirange) Scan(src interface{}) error {
if src == nil {
return dst.DecodeText(nil, nil)
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src Nummultirange) Value() (driver.Value, error) {
return EncodeValueText(src)
}
-853
View File
@@ -1,853 +0,0 @@
package pgtype
import (
"bytes"
"database/sql/driver"
"encoding/binary"
"fmt"
"math"
"math/big"
"strconv"
"strings"
"github.com/jackc/pgio"
)
// PostgreSQL internal numeric storage uses 16-bit "digits" with base of 10,000
const nbase = 10000
const (
pgNumericNaN = 0x00000000c0000000
pgNumericNaNSign = 0xc000
pgNumericPosInf = 0x00000000d0000000
pgNumericPosInfSign = 0xd000
pgNumericNegInf = 0x00000000f0000000
pgNumericNegInfSign = 0xf000
)
var big0 *big.Int = big.NewInt(0)
var big1 *big.Int = big.NewInt(1)
var big10 *big.Int = big.NewInt(10)
var big100 *big.Int = big.NewInt(100)
var big1000 *big.Int = big.NewInt(1000)
var bigMaxInt8 *big.Int = big.NewInt(math.MaxInt8)
var bigMinInt8 *big.Int = big.NewInt(math.MinInt8)
var bigMaxInt16 *big.Int = big.NewInt(math.MaxInt16)
var bigMinInt16 *big.Int = big.NewInt(math.MinInt16)
var bigMaxInt32 *big.Int = big.NewInt(math.MaxInt32)
var bigMinInt32 *big.Int = big.NewInt(math.MinInt32)
var bigMaxInt64 *big.Int = big.NewInt(math.MaxInt64)
var bigMinInt64 *big.Int = big.NewInt(math.MinInt64)
var bigMaxInt *big.Int = big.NewInt(int64(maxInt))
var bigMinInt *big.Int = big.NewInt(int64(minInt))
var bigMaxUint8 *big.Int = big.NewInt(math.MaxUint8)
var bigMaxUint16 *big.Int = big.NewInt(math.MaxUint16)
var bigMaxUint32 *big.Int = big.NewInt(math.MaxUint32)
var bigMaxUint64 *big.Int = (&big.Int{}).SetUint64(uint64(math.MaxUint64))
var bigMaxUint *big.Int = (&big.Int{}).SetUint64(uint64(maxUint))
var bigNBase *big.Int = big.NewInt(nbase)
var bigNBaseX2 *big.Int = big.NewInt(nbase * nbase)
var bigNBaseX3 *big.Int = big.NewInt(nbase * nbase * nbase)
var bigNBaseX4 *big.Int = big.NewInt(nbase * nbase * nbase * nbase)
type Numeric struct {
Int *big.Int
Exp int32
Status Status
NaN bool
InfinityModifier InfinityModifier
}
func (dst *Numeric) Set(src interface{}) error {
if src == nil {
*dst = Numeric{Status: Null}
return nil
}
if value, ok := src.(interface{ Get() interface{} }); ok {
value2 := value.Get()
if value2 != value {
return dst.Set(value2)
}
}
switch value := src.(type) {
case float32:
if math.IsNaN(float64(value)) {
*dst = Numeric{Status: Present, NaN: true}
return nil
} else if math.IsInf(float64(value), 1) {
*dst = Numeric{Status: Present, InfinityModifier: Infinity}
return nil
} else if math.IsInf(float64(value), -1) {
*dst = Numeric{Status: Present, InfinityModifier: NegativeInfinity}
return nil
}
num, exp, err := parseNumericString(strconv.FormatFloat(float64(value), 'f', -1, 64))
if err != nil {
return err
}
*dst = Numeric{Int: num, Exp: exp, Status: Present}
case float64:
if math.IsNaN(value) {
*dst = Numeric{Status: Present, NaN: true}
return nil
} else if math.IsInf(value, 1) {
*dst = Numeric{Status: Present, InfinityModifier: Infinity}
return nil
} else if math.IsInf(value, -1) {
*dst = Numeric{Status: Present, InfinityModifier: NegativeInfinity}
return nil
}
num, exp, err := parseNumericString(strconv.FormatFloat(value, 'f', -1, 64))
if err != nil {
return err
}
*dst = Numeric{Int: num, Exp: exp, Status: Present}
case int8:
*dst = Numeric{Int: big.NewInt(int64(value)), Status: Present}
case uint8:
*dst = Numeric{Int: big.NewInt(int64(value)), Status: Present}
case int16:
*dst = Numeric{Int: big.NewInt(int64(value)), Status: Present}
case uint16:
*dst = Numeric{Int: big.NewInt(int64(value)), Status: Present}
case int32:
*dst = Numeric{Int: big.NewInt(int64(value)), Status: Present}
case uint32:
*dst = Numeric{Int: big.NewInt(int64(value)), Status: Present}
case int64:
*dst = Numeric{Int: big.NewInt(value), Status: Present}
case uint64:
*dst = Numeric{Int: (&big.Int{}).SetUint64(value), Status: Present}
case int:
*dst = Numeric{Int: big.NewInt(int64(value)), Status: Present}
case uint:
*dst = Numeric{Int: (&big.Int{}).SetUint64(uint64(value)), Status: Present}
case string:
num, exp, err := parseNumericString(value)
if err != nil {
return err
}
*dst = Numeric{Int: num, Exp: exp, Status: Present}
case *float64:
if value == nil {
*dst = Numeric{Status: Null}
} else {
return dst.Set(*value)
}
case *float32:
if value == nil {
*dst = Numeric{Status: Null}
} else {
return dst.Set(*value)
}
case *int8:
if value == nil {
*dst = Numeric{Status: Null}
} else {
return dst.Set(*value)
}
case *uint8:
if value == nil {
*dst = Numeric{Status: Null}
} else {
return dst.Set(*value)
}
case *int16:
if value == nil {
*dst = Numeric{Status: Null}
} else {
return dst.Set(*value)
}
case *uint16:
if value == nil {
*dst = Numeric{Status: Null}
} else {
return dst.Set(*value)
}
case *int32:
if value == nil {
*dst = Numeric{Status: Null}
} else {
return dst.Set(*value)
}
case *uint32:
if value == nil {
*dst = Numeric{Status: Null}
} else {
return dst.Set(*value)
}
case *int64:
if value == nil {
*dst = Numeric{Status: Null}
} else {
return dst.Set(*value)
}
case *uint64:
if value == nil {
*dst = Numeric{Status: Null}
} else {
return dst.Set(*value)
}
case *int:
if value == nil {
*dst = Numeric{Status: Null}
} else {
return dst.Set(*value)
}
case *uint:
if value == nil {
*dst = Numeric{Status: Null}
} else {
return dst.Set(*value)
}
case *string:
if value == nil {
*dst = Numeric{Status: Null}
} else {
return dst.Set(*value)
}
case InfinityModifier:
*dst = Numeric{InfinityModifier: value, Status: Present}
default:
if originalSrc, ok := underlyingNumberType(src); ok {
return dst.Set(originalSrc)
}
return fmt.Errorf("cannot convert %v to Numeric", value)
}
return nil
}
func (dst Numeric) Get() interface{} {
switch dst.Status {
case Present:
if dst.InfinityModifier != None {
return dst.InfinityModifier
}
return dst
case Null:
return nil
default:
return dst.Status
}
}
func (src *Numeric) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
switch v := dst.(type) {
case *float32:
f, err := src.toFloat64()
if err != nil {
return err
}
return float64AssignTo(f, src.Status, dst)
case *float64:
f, err := src.toFloat64()
if err != nil {
return err
}
return float64AssignTo(f, src.Status, dst)
case *int:
normalizedInt, err := src.toBigInt()
if err != nil {
return err
}
if normalizedInt.Cmp(bigMaxInt) > 0 {
return fmt.Errorf("%v is greater than maximum value for %T", normalizedInt, *v)
}
if normalizedInt.Cmp(bigMinInt) < 0 {
return fmt.Errorf("%v is less than minimum value for %T", normalizedInt, *v)
}
*v = int(normalizedInt.Int64())
case *int8:
normalizedInt, err := src.toBigInt()
if err != nil {
return err
}
if normalizedInt.Cmp(bigMaxInt8) > 0 {
return fmt.Errorf("%v is greater than maximum value for %T", normalizedInt, *v)
}
if normalizedInt.Cmp(bigMinInt8) < 0 {
return fmt.Errorf("%v is less than minimum value for %T", normalizedInt, *v)
}
*v = int8(normalizedInt.Int64())
case *int16:
normalizedInt, err := src.toBigInt()
if err != nil {
return err
}
if normalizedInt.Cmp(bigMaxInt16) > 0 {
return fmt.Errorf("%v is greater than maximum value for %T", normalizedInt, *v)
}
if normalizedInt.Cmp(bigMinInt16) < 0 {
return fmt.Errorf("%v is less than minimum value for %T", normalizedInt, *v)
}
*v = int16(normalizedInt.Int64())
case *int32:
normalizedInt, err := src.toBigInt()
if err != nil {
return err
}
if normalizedInt.Cmp(bigMaxInt32) > 0 {
return fmt.Errorf("%v is greater than maximum value for %T", normalizedInt, *v)
}
if normalizedInt.Cmp(bigMinInt32) < 0 {
return fmt.Errorf("%v is less than minimum value for %T", normalizedInt, *v)
}
*v = int32(normalizedInt.Int64())
case *int64:
normalizedInt, err := src.toBigInt()
if err != nil {
return err
}
if normalizedInt.Cmp(bigMaxInt64) > 0 {
return fmt.Errorf("%v is greater than maximum value for %T", normalizedInt, *v)
}
if normalizedInt.Cmp(bigMinInt64) < 0 {
return fmt.Errorf("%v is less than minimum value for %T", normalizedInt, *v)
}
*v = normalizedInt.Int64()
case *uint:
normalizedInt, err := src.toBigInt()
if err != nil {
return err
}
if normalizedInt.Cmp(big0) < 0 {
return fmt.Errorf("%d is less than zero for %T", normalizedInt, *v)
} else if normalizedInt.Cmp(bigMaxUint) > 0 {
return fmt.Errorf("%d is greater than maximum value for %T", normalizedInt, *v)
}
*v = uint(normalizedInt.Uint64())
case *uint8:
normalizedInt, err := src.toBigInt()
if err != nil {
return err
}
if normalizedInt.Cmp(big0) < 0 {
return fmt.Errorf("%d is less than zero for %T", normalizedInt, *v)
} else if normalizedInt.Cmp(bigMaxUint8) > 0 {
return fmt.Errorf("%d is greater than maximum value for %T", normalizedInt, *v)
}
*v = uint8(normalizedInt.Uint64())
case *uint16:
normalizedInt, err := src.toBigInt()
if err != nil {
return err
}
if normalizedInt.Cmp(big0) < 0 {
return fmt.Errorf("%d is less than zero for %T", normalizedInt, *v)
} else if normalizedInt.Cmp(bigMaxUint16) > 0 {
return fmt.Errorf("%d is greater than maximum value for %T", normalizedInt, *v)
}
*v = uint16(normalizedInt.Uint64())
case *uint32:
normalizedInt, err := src.toBigInt()
if err != nil {
return err
}
if normalizedInt.Cmp(big0) < 0 {
return fmt.Errorf("%d is less than zero for %T", normalizedInt, *v)
} else if normalizedInt.Cmp(bigMaxUint32) > 0 {
return fmt.Errorf("%d is greater than maximum value for %T", normalizedInt, *v)
}
*v = uint32(normalizedInt.Uint64())
case *uint64:
normalizedInt, err := src.toBigInt()
if err != nil {
return err
}
if normalizedInt.Cmp(big0) < 0 {
return fmt.Errorf("%d is less than zero for %T", normalizedInt, *v)
} else if normalizedInt.Cmp(bigMaxUint64) > 0 {
return fmt.Errorf("%d is greater than maximum value for %T", normalizedInt, *v)
}
*v = normalizedInt.Uint64()
case *big.Rat:
rat, err := src.toBigRat()
if err != nil {
return err
}
v.Set(rat)
case *string:
buf, err := encodeNumericText(*src, nil)
if err != nil {
return err
}
*v = string(buf)
default:
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
return fmt.Errorf("unable to assign to %T", dst)
}
case Null:
return NullAssignTo(dst)
}
return nil
}
func (dst *Numeric) toBigInt() (*big.Int, error) {
if dst.Exp == 0 {
return dst.Int, nil
}
num := &big.Int{}
num.Set(dst.Int)
if dst.Exp > 0 {
mul := &big.Int{}
mul.Exp(big10, big.NewInt(int64(dst.Exp)), nil)
num.Mul(num, mul)
return num, nil
}
div := &big.Int{}
div.Exp(big10, big.NewInt(int64(-dst.Exp)), nil)
remainder := &big.Int{}
num.DivMod(num, div, remainder)
if remainder.Cmp(big0) != 0 {
return nil, fmt.Errorf("cannot convert %v to integer", dst)
}
return num, nil
}
func (dst *Numeric) toBigRat() (*big.Rat, error) {
if dst.NaN {
return nil, fmt.Errorf("%v is not a number", dst)
} else if dst.InfinityModifier == Infinity {
return nil, fmt.Errorf("%v is infinity", dst)
} else if dst.InfinityModifier == NegativeInfinity {
return nil, fmt.Errorf("%v is -infinity", dst)
}
num := new(big.Rat).SetInt(dst.Int)
if dst.Exp > 0 {
mul := new(big.Int).Exp(big10, big.NewInt(int64(dst.Exp)), nil)
num.Mul(num, new(big.Rat).SetInt(mul))
} else if dst.Exp < 0 {
mul := new(big.Int).Exp(big10, big.NewInt(int64(-dst.Exp)), nil)
num.Quo(num, new(big.Rat).SetInt(mul))
}
return num, nil
}
func (src *Numeric) toFloat64() (float64, error) {
if src.NaN {
return math.NaN(), nil
} else if src.InfinityModifier == Infinity {
return math.Inf(1), nil
} else if src.InfinityModifier == NegativeInfinity {
return math.Inf(-1), nil
}
buf := make([]byte, 0, 32)
buf = append(buf, src.Int.String()...)
buf = append(buf, 'e')
buf = append(buf, strconv.FormatInt(int64(src.Exp), 10)...)
f, err := strconv.ParseFloat(string(buf), 64)
if err != nil {
return 0, err
}
return f, nil
}
func (dst *Numeric) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Numeric{Status: Null}
return nil
}
if string(src) == "NaN" {
*dst = Numeric{Status: Present, NaN: true}
return nil
} else if string(src) == "Infinity" {
*dst = Numeric{Status: Present, InfinityModifier: Infinity}
return nil
} else if string(src) == "-Infinity" {
*dst = Numeric{Status: Present, InfinityModifier: NegativeInfinity}
return nil
}
num, exp, err := parseNumericString(string(src))
if err != nil {
return err
}
*dst = Numeric{Int: num, Exp: exp, Status: Present}
return nil
}
func parseNumericString(str string) (n *big.Int, exp int32, err error) {
parts := strings.SplitN(str, ".", 2)
digits := strings.Join(parts, "")
if len(parts) > 1 {
exp = int32(-len(parts[1]))
} else {
for len(digits) > 1 && digits[len(digits)-1] == '0' && digits[len(digits)-2] != '-' {
digits = digits[:len(digits)-1]
exp++
}
}
accum := &big.Int{}
if _, ok := accum.SetString(digits, 10); !ok {
return nil, 0, fmt.Errorf("%s is not a number", str)
}
return accum, exp, nil
}
func (dst *Numeric) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Numeric{Status: Null}
return nil
}
if len(src) < 8 {
return fmt.Errorf("numeric incomplete %v", src)
}
rp := 0
ndigits := binary.BigEndian.Uint16(src[rp:])
rp += 2
weight := int16(binary.BigEndian.Uint16(src[rp:]))
rp += 2
sign := binary.BigEndian.Uint16(src[rp:])
rp += 2
dscale := int16(binary.BigEndian.Uint16(src[rp:]))
rp += 2
if sign == pgNumericNaNSign {
*dst = Numeric{Status: Present, NaN: true}
return nil
} else if sign == pgNumericPosInfSign {
*dst = Numeric{Status: Present, InfinityModifier: Infinity}
return nil
} else if sign == pgNumericNegInfSign {
*dst = Numeric{Status: Present, InfinityModifier: NegativeInfinity}
return nil
}
if ndigits == 0 {
*dst = Numeric{Int: big.NewInt(0), Status: Present}
return nil
}
if len(src[rp:]) < int(ndigits)*2 {
return fmt.Errorf("numeric incomplete %v", src)
}
accum := &big.Int{}
for i := 0; i < int(ndigits+3)/4; i++ {
int64accum, bytesRead, digitsRead := nbaseDigitsToInt64(src[rp:])
rp += bytesRead
if i > 0 {
var mul *big.Int
switch digitsRead {
case 1:
mul = bigNBase
case 2:
mul = bigNBaseX2
case 3:
mul = bigNBaseX3
case 4:
mul = bigNBaseX4
default:
return fmt.Errorf("invalid digitsRead: %d (this can't happen)", digitsRead)
}
accum.Mul(accum, mul)
}
accum.Add(accum, big.NewInt(int64accum))
}
exp := (int32(weight) - int32(ndigits) + 1) * 4
if dscale > 0 {
fracNBaseDigits := int16(int32(ndigits) - int32(weight) - 1)
fracDecimalDigits := fracNBaseDigits * 4
if dscale > fracDecimalDigits {
multCount := int(dscale - fracDecimalDigits)
for i := 0; i < multCount; i++ {
accum.Mul(accum, big10)
exp--
}
} else if dscale < fracDecimalDigits {
divCount := int(fracDecimalDigits - dscale)
for i := 0; i < divCount; i++ {
accum.Div(accum, big10)
exp++
}
}
}
reduced := &big.Int{}
remainder := &big.Int{}
if exp >= 0 {
for {
reduced.DivMod(accum, big10, remainder)
if remainder.Cmp(big0) != 0 {
break
}
accum.Set(reduced)
exp++
}
}
if sign != 0 {
accum.Neg(accum)
}
*dst = Numeric{Int: accum, Exp: exp, Status: Present}
return nil
}
func nbaseDigitsToInt64(src []byte) (accum int64, bytesRead, digitsRead int) {
digits := len(src) / 2
if digits > 4 {
digits = 4
}
rp := 0
for i := 0; i < digits; i++ {
if i > 0 {
accum *= nbase
}
accum += int64(binary.BigEndian.Uint16(src[rp:]))
rp += 2
}
return accum, rp, digits
}
func (src Numeric) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
if src.NaN {
buf = append(buf, "NaN"...)
return buf, nil
} else if src.InfinityModifier == Infinity {
buf = append(buf, "Infinity"...)
return buf, nil
} else if src.InfinityModifier == NegativeInfinity {
buf = append(buf, "-Infinity"...)
return buf, nil
}
buf = append(buf, src.Int.String()...)
buf = append(buf, 'e')
buf = append(buf, strconv.FormatInt(int64(src.Exp), 10)...)
return buf, nil
}
func (src Numeric) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
if src.NaN {
buf = pgio.AppendUint64(buf, pgNumericNaN)
return buf, nil
} else if src.InfinityModifier == Infinity {
buf = pgio.AppendUint64(buf, pgNumericPosInf)
return buf, nil
} else if src.InfinityModifier == NegativeInfinity {
buf = pgio.AppendUint64(buf, pgNumericNegInf)
return buf, nil
}
var sign int16
if src.Int.Cmp(big0) < 0 {
sign = 16384
}
absInt := &big.Int{}
wholePart := &big.Int{}
fracPart := &big.Int{}
remainder := &big.Int{}
absInt.Abs(src.Int)
// Normalize absInt and exp to where exp is always a multiple of 4. This makes
// converting to 16-bit base 10,000 digits easier.
var exp int32
switch src.Exp % 4 {
case 1, -3:
exp = src.Exp - 1
absInt.Mul(absInt, big10)
case 2, -2:
exp = src.Exp - 2
absInt.Mul(absInt, big100)
case 3, -1:
exp = src.Exp - 3
absInt.Mul(absInt, big1000)
default:
exp = src.Exp
}
if exp < 0 {
divisor := &big.Int{}
divisor.Exp(big10, big.NewInt(int64(-exp)), nil)
wholePart.DivMod(absInt, divisor, fracPart)
fracPart.Add(fracPart, divisor)
} else {
wholePart = absInt
}
var wholeDigits, fracDigits []int16
for wholePart.Cmp(big0) != 0 {
wholePart.DivMod(wholePart, bigNBase, remainder)
wholeDigits = append(wholeDigits, int16(remainder.Int64()))
}
if fracPart.Cmp(big0) != 0 {
for fracPart.Cmp(big1) != 0 {
fracPart.DivMod(fracPart, bigNBase, remainder)
fracDigits = append(fracDigits, int16(remainder.Int64()))
}
}
buf = pgio.AppendInt16(buf, int16(len(wholeDigits)+len(fracDigits)))
var weight int16
if len(wholeDigits) > 0 {
weight = int16(len(wholeDigits) - 1)
if exp > 0 {
weight += int16(exp / 4)
}
} else {
weight = int16(exp/4) - 1 + int16(len(fracDigits))
}
buf = pgio.AppendInt16(buf, weight)
buf = pgio.AppendInt16(buf, sign)
var dscale int16
if src.Exp < 0 {
dscale = int16(-src.Exp)
}
buf = pgio.AppendInt16(buf, dscale)
for i := len(wholeDigits) - 1; i >= 0; i-- {
buf = pgio.AppendInt16(buf, wholeDigits[i])
}
for i := len(fracDigits) - 1; i >= 0; i-- {
buf = pgio.AppendInt16(buf, fracDigits[i])
}
return buf, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *Numeric) Scan(src interface{}) error {
if src == nil {
*dst = Numeric{Status: Null}
return nil
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src Numeric) Value() (driver.Value, error) {
switch src.Status {
case Present:
buf, err := src.EncodeText(nil, nil)
if err != nil {
return nil, err
}
return string(buf), nil
case Null:
return nil, nil
default:
return nil, errUndefined
}
}
func encodeNumericText(n Numeric, buf []byte) (newBuf []byte, err error) {
// if !n.Valid {
// return nil, nil
// }
if n.NaN {
buf = append(buf, "NaN"...)
return buf, nil
} else if n.InfinityModifier == Infinity {
buf = append(buf, "Infinity"...)
return buf, nil
} else if n.InfinityModifier == NegativeInfinity {
buf = append(buf, "-Infinity"...)
return buf, nil
}
buf = append(buf, n.numberTextBytes()...)
return buf, nil
}
// numberString returns a string of the number. undefined if NaN, infinite, or NULL
func (n Numeric) numberTextBytes() []byte {
intStr := n.Int.String()
buf := &bytes.Buffer{}
exp := int(n.Exp)
if exp > 0 {
buf.WriteString(intStr)
for i := 0; i < exp; i++ {
buf.WriteByte('0')
}
} else if exp < 0 {
if len(intStr) <= -exp {
buf.WriteString("0.")
leadingZeros := -exp - len(intStr)
for i := 0; i < leadingZeros; i++ {
buf.WriteByte('0')
}
buf.WriteString(intStr)
} else if len(intStr) > -exp {
dpPos := len(intStr) + exp
buf.WriteString(intStr[:dpPos])
buf.WriteByte('.')
buf.WriteString(intStr[dpPos:])
}
} else {
buf.WriteString(intStr)
}
return buf.Bytes()
}
-685
View File
@@ -1,685 +0,0 @@
// Code generated by erb. DO NOT EDIT.
package pgtype
import (
"database/sql/driver"
"encoding/binary"
"fmt"
"reflect"
"github.com/jackc/pgio"
)
type NumericArray struct {
Elements []Numeric
Dimensions []ArrayDimension
Status Status
}
func (dst *NumericArray) Set(src interface{}) error {
// untyped nil and typed nil interfaces are different
if src == nil {
*dst = NumericArray{Status: Null}
return nil
}
if value, ok := src.(interface{ Get() interface{} }); ok {
value2 := value.Get()
if value2 != value {
return dst.Set(value2)
}
}
// Attempt to match to select common types:
switch value := src.(type) {
case []float32:
if value == nil {
*dst = NumericArray{Status: Null}
} else if len(value) == 0 {
*dst = NumericArray{Status: Present}
} else {
elements := make([]Numeric, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = NumericArray{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []*float32:
if value == nil {
*dst = NumericArray{Status: Null}
} else if len(value) == 0 {
*dst = NumericArray{Status: Present}
} else {
elements := make([]Numeric, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = NumericArray{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []float64:
if value == nil {
*dst = NumericArray{Status: Null}
} else if len(value) == 0 {
*dst = NumericArray{Status: Present}
} else {
elements := make([]Numeric, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = NumericArray{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []*float64:
if value == nil {
*dst = NumericArray{Status: Null}
} else if len(value) == 0 {
*dst = NumericArray{Status: Present}
} else {
elements := make([]Numeric, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = NumericArray{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []int64:
if value == nil {
*dst = NumericArray{Status: Null}
} else if len(value) == 0 {
*dst = NumericArray{Status: Present}
} else {
elements := make([]Numeric, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = NumericArray{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []*int64:
if value == nil {
*dst = NumericArray{Status: Null}
} else if len(value) == 0 {
*dst = NumericArray{Status: Present}
} else {
elements := make([]Numeric, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = NumericArray{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []uint64:
if value == nil {
*dst = NumericArray{Status: Null}
} else if len(value) == 0 {
*dst = NumericArray{Status: Present}
} else {
elements := make([]Numeric, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = NumericArray{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []*uint64:
if value == nil {
*dst = NumericArray{Status: Null}
} else if len(value) == 0 {
*dst = NumericArray{Status: Present}
} else {
elements := make([]Numeric, len(value))
for i := range value {
if err := elements[i].Set(value[i]); err != nil {
return err
}
}
*dst = NumericArray{
Elements: elements,
Dimensions: []ArrayDimension{{Length: int32(len(elements)), LowerBound: 1}},
Status: Present,
}
}
case []Numeric:
if value == nil {
*dst = NumericArray{Status: Null}
} else if len(value) == 0 {
*dst = NumericArray{Status: Present}
} else {
*dst = NumericArray{
Elements: value,
Dimensions: []ArrayDimension{{Length: int32(len(value)), LowerBound: 1}},
Status: Present,
}
}
default:
// Fallback to reflection if an optimised match was not found.
// The reflection is necessary for arrays and multidimensional slices,
// but it comes with a 20-50% performance penalty for large arrays/slices
reflectedValue := reflect.ValueOf(src)
if !reflectedValue.IsValid() || reflectedValue.IsZero() {
*dst = NumericArray{Status: Null}
return nil
}
dimensions, elementsLength, ok := findDimensionsFromValue(reflectedValue, nil, 0)
if !ok {
return fmt.Errorf("cannot find dimensions of %v for NumericArray", src)
}
if elementsLength == 0 {
*dst = NumericArray{Status: Present}
return nil
}
if len(dimensions) == 0 {
if originalSrc, ok := underlyingSliceType(src); ok {
return dst.Set(originalSrc)
}
return fmt.Errorf("cannot convert %v to NumericArray", src)
}
*dst = NumericArray{
Elements: make([]Numeric, elementsLength),
Dimensions: dimensions,
Status: Present,
}
elementCount, err := dst.setRecursive(reflectedValue, 0, 0)
if err != nil {
// Maybe the target was one dimension too far, try again:
if len(dst.Dimensions) > 1 {
dst.Dimensions = dst.Dimensions[:len(dst.Dimensions)-1]
elementsLength = 0
for _, dim := range dst.Dimensions {
if elementsLength == 0 {
elementsLength = int(dim.Length)
} else {
elementsLength *= int(dim.Length)
}
}
dst.Elements = make([]Numeric, elementsLength)
elementCount, err = dst.setRecursive(reflectedValue, 0, 0)
if err != nil {
return err
}
} else {
return err
}
}
if elementCount != len(dst.Elements) {
return fmt.Errorf("cannot convert %v to NumericArray, expected %d dst.Elements, but got %d instead", src, len(dst.Elements), elementCount)
}
}
return nil
}
func (dst *NumericArray) setRecursive(value reflect.Value, index, dimension int) (int, error) {
switch value.Kind() {
case reflect.Array:
fallthrough
case reflect.Slice:
if len(dst.Dimensions) == dimension {
break
}
valueLen := value.Len()
if int32(valueLen) != dst.Dimensions[dimension].Length {
return 0, fmt.Errorf("multidimensional arrays must have array expressions with matching dimensions")
}
for i := 0; i < valueLen; i++ {
var err error
index, err = dst.setRecursive(value.Index(i), index, dimension+1)
if err != nil {
return 0, err
}
}
return index, nil
}
if !value.CanInterface() {
return 0, fmt.Errorf("cannot convert all values to NumericArray")
}
if err := dst.Elements[index].Set(value.Interface()); err != nil {
return 0, fmt.Errorf("%v in NumericArray", err)
}
index++
return index, nil
}
func (dst NumericArray) Get() interface{} {
switch dst.Status {
case Present:
return dst
case Null:
return nil
default:
return dst.Status
}
}
func (src *NumericArray) AssignTo(dst interface{}) error {
switch src.Status {
case Present:
if len(src.Dimensions) <= 1 {
// Attempt to match to select common types:
switch v := dst.(type) {
case *[]float32:
*v = make([]float32, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]*float32:
*v = make([]*float32, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]float64:
*v = make([]float64, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]*float64:
*v = make([]*float64, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]int64:
*v = make([]int64, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]*int64:
*v = make([]*int64, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]uint64:
*v = make([]uint64, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
case *[]*uint64:
*v = make([]*uint64, len(src.Elements))
for i := range src.Elements {
if err := src.Elements[i].AssignTo(&((*v)[i])); err != nil {
return err
}
}
return nil
}
}
// Try to convert to something AssignTo can use directly.
if nextDst, retry := GetAssignToDstType(dst); retry {
return src.AssignTo(nextDst)
}
// Fallback to reflection if an optimised match was not found.
// The reflection is necessary for arrays and multidimensional slices,
// but it comes with a 20-50% performance penalty for large arrays/slices
value := reflect.ValueOf(dst)
if value.Kind() == reflect.Ptr {
value = value.Elem()
}
switch value.Kind() {
case reflect.Array, reflect.Slice:
default:
return fmt.Errorf("cannot assign %T to %T", src, dst)
}
if len(src.Elements) == 0 {
if value.Kind() == reflect.Slice {
value.Set(reflect.MakeSlice(value.Type(), 0, 0))
return nil
}
}
elementCount, err := src.assignToRecursive(value, 0, 0)
if err != nil {
return err
}
if elementCount != len(src.Elements) {
return fmt.Errorf("cannot assign %v, needed to assign %d elements, but only assigned %d", dst, len(src.Elements), elementCount)
}
return nil
case Null:
return NullAssignTo(dst)
}
return fmt.Errorf("cannot decode %#v into %T", src, dst)
}
func (src *NumericArray) assignToRecursive(value reflect.Value, index, dimension int) (int, error) {
switch kind := value.Kind(); kind {
case reflect.Array:
fallthrough
case reflect.Slice:
if len(src.Dimensions) == dimension {
break
}
length := int(src.Dimensions[dimension].Length)
if reflect.Array == kind {
typ := value.Type()
if typ.Len() != length {
return 0, fmt.Errorf("expected size %d array, but %s has size %d array", length, typ, typ.Len())
}
value.Set(reflect.New(typ).Elem())
} else {
value.Set(reflect.MakeSlice(value.Type(), length, length))
}
var err error
for i := 0; i < length; i++ {
index, err = src.assignToRecursive(value.Index(i), index, dimension+1)
if err != nil {
return 0, err
}
}
return index, nil
}
if len(src.Dimensions) != dimension {
return 0, fmt.Errorf("incorrect dimensions, expected %d, found %d", len(src.Dimensions), dimension)
}
if !value.CanAddr() {
return 0, fmt.Errorf("cannot assign all values from NumericArray")
}
addr := value.Addr()
if !addr.CanInterface() {
return 0, fmt.Errorf("cannot assign all values from NumericArray")
}
if err := src.Elements[index].AssignTo(addr.Interface()); err != nil {
return 0, err
}
index++
return index, nil
}
func (dst *NumericArray) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = NumericArray{Status: Null}
return nil
}
uta, err := ParseUntypedTextArray(string(src))
if err != nil {
return err
}
var elements []Numeric
if len(uta.Elements) > 0 {
elements = make([]Numeric, len(uta.Elements))
for i, s := range uta.Elements {
var elem Numeric
var elemSrc []byte
if s != "NULL" || uta.Quoted[i] {
elemSrc = []byte(s)
}
err = elem.DecodeText(ci, elemSrc)
if err != nil {
return err
}
elements[i] = elem
}
}
*dst = NumericArray{Elements: elements, Dimensions: uta.Dimensions, Status: Present}
return nil
}
func (dst *NumericArray) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = NumericArray{Status: Null}
return nil
}
var arrayHeader ArrayHeader
rp, err := arrayHeader.DecodeBinary(ci, src)
if err != nil {
return err
}
if len(arrayHeader.Dimensions) == 0 {
*dst = NumericArray{Dimensions: arrayHeader.Dimensions, Status: Present}
return nil
}
elementCount := arrayHeader.Dimensions[0].Length
for _, d := range arrayHeader.Dimensions[1:] {
elementCount *= d.Length
}
elements := make([]Numeric, elementCount)
for i := range elements {
elemLen := int(int32(binary.BigEndian.Uint32(src[rp:])))
rp += 4
var elemSrc []byte
if elemLen >= 0 {
elemSrc = src[rp : rp+elemLen]
rp += elemLen
}
err = elements[i].DecodeBinary(ci, elemSrc)
if err != nil {
return err
}
}
*dst = NumericArray{Elements: elements, Dimensions: arrayHeader.Dimensions, Status: Present}
return nil
}
func (src NumericArray) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
if len(src.Dimensions) == 0 {
return append(buf, '{', '}'), nil
}
buf = EncodeTextArrayDimensions(buf, src.Dimensions)
// dimElemCounts is the multiples of elements that each array lies on. For
// example, a single dimension array of length 4 would have a dimElemCounts of
// [4]. A multi-dimensional array of lengths [3,5,2] would have a
// dimElemCounts of [30,10,2]. This is used to simplify when to render a '{'
// or '}'.
dimElemCounts := make([]int, len(src.Dimensions))
dimElemCounts[len(src.Dimensions)-1] = int(src.Dimensions[len(src.Dimensions)-1].Length)
for i := len(src.Dimensions) - 2; i > -1; i-- {
dimElemCounts[i] = int(src.Dimensions[i].Length) * dimElemCounts[i+1]
}
inElemBuf := make([]byte, 0, 32)
for i, elem := range src.Elements {
if i > 0 {
buf = append(buf, ',')
}
for _, dec := range dimElemCounts {
if i%dec == 0 {
buf = append(buf, '{')
}
}
elemBuf, err := elem.EncodeText(ci, inElemBuf)
if err != nil {
return nil, err
}
if elemBuf == nil {
buf = append(buf, `NULL`...)
} else {
buf = append(buf, QuoteArrayElementIfNeeded(string(elemBuf))...)
}
for _, dec := range dimElemCounts {
if (i+1)%dec == 0 {
buf = append(buf, '}')
}
}
}
return buf, nil
}
func (src NumericArray) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
arrayHeader := ArrayHeader{
Dimensions: src.Dimensions,
}
if dt, ok := ci.DataTypeForName("numeric"); ok {
arrayHeader.ElementOID = int32(dt.OID)
} else {
return nil, fmt.Errorf("unable to find oid for type name %v", "numeric")
}
for i := range src.Elements {
if src.Elements[i].Status == Null {
arrayHeader.ContainsNull = true
break
}
}
buf = arrayHeader.EncodeBinary(ci, buf)
for i := range src.Elements {
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
elemBuf, err := src.Elements[i].EncodeBinary(ci, buf)
if err != nil {
return nil, err
}
if elemBuf != nil {
buf = elemBuf
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
}
return buf, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *NumericArray) Scan(src interface{}) error {
if src == nil {
return dst.DecodeText(nil, nil)
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src NumericArray) Value() (driver.Value, error) {
buf, err := src.EncodeText(nil, nil)
if err != nil {
return nil, err
}
if buf == nil {
return nil, nil
}
return string(buf), nil
}
-267
View File
@@ -1,267 +0,0 @@
package pgtype
import (
"database/sql/driver"
"fmt"
"github.com/jackc/pgio"
)
type Numrange struct {
Lower Numeric
Upper Numeric
LowerType BoundType
UpperType BoundType
Status Status
}
func (dst *Numrange) Set(src interface{}) error {
// untyped nil and typed nil interfaces are different
if src == nil {
*dst = Numrange{Status: Null}
return nil
}
switch value := src.(type) {
case Numrange:
*dst = value
case *Numrange:
*dst = *value
case string:
return dst.DecodeText(nil, []byte(value))
default:
return fmt.Errorf("cannot convert %v to Numrange", src)
}
return nil
}
func (dst Numrange) Get() interface{} {
switch dst.Status {
case Present:
return dst
case Null:
return nil
default:
return dst.Status
}
}
func (src *Numrange) AssignTo(dst interface{}) error {
return fmt.Errorf("cannot assign %v to %T", src, dst)
}
func (dst *Numrange) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Numrange{Status: Null}
return nil
}
utr, err := ParseUntypedTextRange(string(src))
if err != nil {
return err
}
*dst = Numrange{Status: Present}
dst.LowerType = utr.LowerType
dst.UpperType = utr.UpperType
if dst.LowerType == Empty {
return nil
}
if dst.LowerType == Inclusive || dst.LowerType == Exclusive {
if err := dst.Lower.DecodeText(ci, []byte(utr.Lower)); err != nil {
return err
}
}
if dst.UpperType == Inclusive || dst.UpperType == Exclusive {
if err := dst.Upper.DecodeText(ci, []byte(utr.Upper)); err != nil {
return err
}
}
return nil
}
func (dst *Numrange) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Numrange{Status: Null}
return nil
}
ubr, err := ParseUntypedBinaryRange(src)
if err != nil {
return err
}
*dst = Numrange{Status: Present}
dst.LowerType = ubr.LowerType
dst.UpperType = ubr.UpperType
if dst.LowerType == Empty {
return nil
}
if dst.LowerType == Inclusive || dst.LowerType == Exclusive {
if err := dst.Lower.DecodeBinary(ci, ubr.Lower); err != nil {
return err
}
}
if dst.UpperType == Inclusive || dst.UpperType == Exclusive {
if err := dst.Upper.DecodeBinary(ci, ubr.Upper); err != nil {
return err
}
}
return nil
}
func (src Numrange) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
switch src.LowerType {
case Exclusive, Unbounded:
buf = append(buf, '(')
case Inclusive:
buf = append(buf, '[')
case Empty:
return append(buf, "empty"...), nil
default:
return nil, fmt.Errorf("unknown lower bound type %v", src.LowerType)
}
var err error
if src.LowerType != Unbounded {
buf, err = src.Lower.EncodeText(ci, buf)
if err != nil {
return nil, err
} else if buf == nil {
return nil, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
}
}
buf = append(buf, ',')
if src.UpperType != Unbounded {
buf, err = src.Upper.EncodeText(ci, buf)
if err != nil {
return nil, err
} else if buf == nil {
return nil, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
}
}
switch src.UpperType {
case Exclusive, Unbounded:
buf = append(buf, ')')
case Inclusive:
buf = append(buf, ']')
default:
return nil, fmt.Errorf("unknown upper bound type %v", src.UpperType)
}
return buf, nil
}
func (src Numrange) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
var rangeType byte
switch src.LowerType {
case Inclusive:
rangeType |= lowerInclusiveMask
case Unbounded:
rangeType |= lowerUnboundedMask
case Exclusive:
case Empty:
return append(buf, emptyMask), nil
default:
return nil, fmt.Errorf("unknown LowerType: %v", src.LowerType)
}
switch src.UpperType {
case Inclusive:
rangeType |= upperInclusiveMask
case Unbounded:
rangeType |= upperUnboundedMask
case Exclusive:
default:
return nil, fmt.Errorf("unknown UpperType: %v", src.UpperType)
}
buf = append(buf, rangeType)
var err error
if src.LowerType != Unbounded {
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
buf, err = src.Lower.EncodeBinary(ci, buf)
if err != nil {
return nil, err
}
if buf == nil {
return nil, fmt.Errorf("Lower cannot be null unless LowerType is Unbounded")
}
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
if src.UpperType != Unbounded {
sp := len(buf)
buf = pgio.AppendInt32(buf, -1)
buf, err = src.Upper.EncodeBinary(ci, buf)
if err != nil {
return nil, err
}
if buf == nil {
return nil, fmt.Errorf("Upper cannot be null unless UpperType is Unbounded")
}
pgio.SetInt32(buf[sp:], int32(len(buf[sp:])-4))
}
return buf, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *Numrange) Scan(src interface{}) error {
if src == nil {
*dst = Numrange{Status: Null}
return nil
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src Numrange) Value() (driver.Value, error) {
return EncodeValueText(src)
}
-81
View File
@@ -1,81 +0,0 @@
package pgtype
import (
"database/sql/driver"
"encoding/binary"
"fmt"
"strconv"
"github.com/jackc/pgio"
)
// OID (Object Identifier Type) is, according to
// https://www.postgresql.org/docs/current/static/datatype-oid.html, used
// internally by PostgreSQL as a primary key for various system tables. It is
// currently implemented as an unsigned four-byte integer. Its definition can be
// found in src/include/postgres_ext.h in the PostgreSQL sources. Because it is
// so frequently required to be in a NOT NULL condition OID cannot be NULL. To
// allow for NULL OIDs use OIDValue.
type OID uint32
func (dst *OID) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
return fmt.Errorf("cannot decode nil into OID")
}
n, err := strconv.ParseUint(string(src), 10, 32)
if err != nil {
return err
}
*dst = OID(n)
return nil
}
func (dst *OID) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
return fmt.Errorf("cannot decode nil into OID")
}
if len(src) != 4 {
return fmt.Errorf("invalid length: %v", len(src))
}
n := binary.BigEndian.Uint32(src)
*dst = OID(n)
return nil
}
func (src OID) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
return append(buf, strconv.FormatUint(uint64(src), 10)...), nil
}
func (src OID) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
return pgio.AppendUint32(buf, uint32(src)), nil
}
// Scan implements the database/sql Scanner interface.
func (dst *OID) Scan(src interface{}) error {
if src == nil {
return fmt.Errorf("cannot scan NULL into %T", src)
}
switch src := src.(type) {
case int64:
*dst = OID(src)
return nil
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src OID) Value() (driver.Value, error) {
return int64(src), nil
}
-55
View File
@@ -1,55 +0,0 @@
package pgtype
import (
"database/sql/driver"
)
// OIDValue (Object Identifier Type) is, according to
// https://www.postgresql.org/docs/current/static/datatype-OIDValue.html, used
// internally by PostgreSQL as a primary key for various system tables. It is
// currently implemented as an unsigned four-byte integer. Its definition can be
// found in src/include/postgres_ext.h in the PostgreSQL sources.
type OIDValue pguint32
// Set converts from src to dst. Note that as OIDValue is not a general
// number type Set does not do automatic type conversion as other number
// types do.
func (dst *OIDValue) Set(src interface{}) error {
return (*pguint32)(dst).Set(src)
}
func (dst OIDValue) Get() interface{} {
return (pguint32)(dst).Get()
}
// AssignTo assigns from src to dst. Note that as OIDValue is not a general number
// type AssignTo does not do automatic type conversion as other number types do.
func (src *OIDValue) AssignTo(dst interface{}) error {
return (*pguint32)(src).AssignTo(dst)
}
func (dst *OIDValue) DecodeText(ci *ConnInfo, src []byte) error {
return (*pguint32)(dst).DecodeText(ci, src)
}
func (dst *OIDValue) DecodeBinary(ci *ConnInfo, src []byte) error {
return (*pguint32)(dst).DecodeBinary(ci, src)
}
func (src OIDValue) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
return (pguint32)(src).EncodeText(ci, buf)
}
func (src OIDValue) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
return (pguint32)(src).EncodeBinary(ci, buf)
}
// Scan implements the database/sql Scanner interface.
func (dst *OIDValue) Scan(src interface{}) error {
return (*pguint32)(dst).Scan(src)
}
// Value implements the database/sql/driver Valuer interface.
func (src OIDValue) Value() (driver.Value, error) {
return (pguint32)(src).Value()
}
-195
View File
@@ -1,195 +0,0 @@
package pgtype
import (
"database/sql/driver"
"encoding/binary"
"fmt"
"math"
"strconv"
"strings"
"github.com/jackc/pgio"
)
type Path struct {
P []Vec2
Closed bool
Status Status
}
func (dst *Path) Set(src interface{}) error {
return fmt.Errorf("cannot convert %v to Path", src)
}
func (dst Path) Get() interface{} {
switch dst.Status {
case Present:
return dst
case Null:
return nil
default:
return dst.Status
}
}
func (src *Path) AssignTo(dst interface{}) error {
return fmt.Errorf("cannot assign %v to %T", src, dst)
}
func (dst *Path) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Path{Status: Null}
return nil
}
if len(src) < 7 {
return fmt.Errorf("invalid length for Path: %v", len(src))
}
closed := src[0] == '('
points := make([]Vec2, 0)
str := string(src[2:])
for {
end := strings.IndexByte(str, ',')
x, err := strconv.ParseFloat(str[:end], 64)
if err != nil {
return err
}
str = str[end+1:]
end = strings.IndexByte(str, ')')
y, err := strconv.ParseFloat(str[:end], 64)
if err != nil {
return err
}
points = append(points, Vec2{x, y})
if end+3 < len(str) {
str = str[end+3:]
} else {
break
}
}
*dst = Path{P: points, Closed: closed, Status: Present}
return nil
}
func (dst *Path) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = Path{Status: Null}
return nil
}
if len(src) < 5 {
return fmt.Errorf("invalid length for Path: %v", len(src))
}
closed := src[0] == 1
pointCount := int(binary.BigEndian.Uint32(src[1:]))
rp := 5
if 5+pointCount*16 != len(src) {
return fmt.Errorf("invalid length for Path with %d points: %v", pointCount, len(src))
}
points := make([]Vec2, pointCount)
for i := 0; i < len(points); i++ {
x := binary.BigEndian.Uint64(src[rp:])
rp += 8
y := binary.BigEndian.Uint64(src[rp:])
rp += 8
points[i] = Vec2{math.Float64frombits(x), math.Float64frombits(y)}
}
*dst = Path{
P: points,
Closed: closed,
Status: Present,
}
return nil
}
func (src Path) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
var startByte, endByte byte
if src.Closed {
startByte = '('
endByte = ')'
} else {
startByte = '['
endByte = ']'
}
buf = append(buf, startByte)
for i, p := range src.P {
if i > 0 {
buf = append(buf, ',')
}
buf = append(buf, fmt.Sprintf(`(%s,%s)`,
strconv.FormatFloat(p.X, 'f', -1, 64),
strconv.FormatFloat(p.Y, 'f', -1, 64),
)...)
}
return append(buf, endByte), nil
}
func (src Path) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
var closeByte byte
if src.Closed {
closeByte = 1
}
buf = append(buf, closeByte)
buf = pgio.AppendInt32(buf, int32(len(src.P)))
for _, p := range src.P {
buf = pgio.AppendUint64(buf, math.Float64bits(p.X))
buf = pgio.AppendUint64(buf, math.Float64bits(p.Y))
}
return buf, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *Path) Scan(src interface{}) error {
if src == nil {
*dst = Path{Status: Null}
return nil
}
switch src := src.(type) {
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src Path) Value() (driver.Value, error) {
return EncodeValueText(src)
}
-1000
View File
@@ -1,1000 +0,0 @@
package pgtype
import (
"database/sql"
"encoding/binary"
"errors"
"fmt"
"math"
"net"
"reflect"
"time"
)
// PostgreSQL oids for common types
const (
BoolOID = 16
ByteaOID = 17
QCharOID = 18
NameOID = 19
Int8OID = 20
Int2OID = 21
Int4OID = 23
TextOID = 25
OIDOID = 26
TIDOID = 27
XIDOID = 28
CIDOID = 29
JSONOID = 114
JSONArrayOID = 199
PointOID = 600
LsegOID = 601
PathOID = 602
BoxOID = 603
PolygonOID = 604
LineOID = 628
CIDROID = 650
CIDRArrayOID = 651
Float4OID = 700
Float8OID = 701
CircleOID = 718
UnknownOID = 705
MacaddrOID = 829
InetOID = 869
BoolArrayOID = 1000
Int2ArrayOID = 1005
Int4ArrayOID = 1007
TextArrayOID = 1009
ByteaArrayOID = 1001
BPCharArrayOID = 1014
VarcharArrayOID = 1015
Int8ArrayOID = 1016
Float4ArrayOID = 1021
Float8ArrayOID = 1022
ACLItemOID = 1033
ACLItemArrayOID = 1034
InetArrayOID = 1041
BPCharOID = 1042
VarcharOID = 1043
DateOID = 1082
TimeOID = 1083
TimestampOID = 1114
TimestampArrayOID = 1115
DateArrayOID = 1182
TimestamptzOID = 1184
TimestamptzArrayOID = 1185
IntervalOID = 1186
NumericArrayOID = 1231
BitOID = 1560
VarbitOID = 1562
NumericOID = 1700
RecordOID = 2249
UUIDOID = 2950
UUIDArrayOID = 2951
JSONBOID = 3802
JSONBArrayOID = 3807
DaterangeOID = 3912
Int4rangeOID = 3904
Int4multirangeOID = 4451
NumrangeOID = 3906
NummultirangeOID = 4532
TsrangeOID = 3908
TsrangeArrayOID = 3909
TstzrangeOID = 3910
TstzrangeArrayOID = 3911
Int8rangeOID = 3926
Int8multirangeOID = 4536
)
type Status byte
const (
Undefined Status = iota
Null
Present
)
type InfinityModifier int8
const (
Infinity InfinityModifier = 1
None InfinityModifier = 0
NegativeInfinity InfinityModifier = -Infinity
)
func (im InfinityModifier) String() string {
switch im {
case None:
return "none"
case Infinity:
return "infinity"
case NegativeInfinity:
return "-infinity"
default:
return "invalid"
}
}
// PostgreSQL format codes
const (
TextFormatCode = 0
BinaryFormatCode = 1
)
// Value translates values to and from an internal canonical representation for the type. To actually be usable a type
// that implements Value should also implement some combination of BinaryDecoder, BinaryEncoder, TextDecoder,
// and TextEncoder.
//
// Operations that update a Value (e.g. Set, DecodeText, DecodeBinary) should entirely replace the value. e.g. Internal
// slices should be replaced not resized and reused. This allows Get and AssignTo to return a slice directly rather
// than incur a usually unnecessary copy.
type Value interface {
// Set converts and assigns src to itself. Value takes ownership of src.
Set(src interface{}) error
// Get returns the simplest representation of Value. Get may return a pointer to an internal value but it must never
// mutate that value. e.g. If Get returns a []byte Value must never change the contents of the []byte.
Get() interface{}
// AssignTo converts and assigns the Value to dst. AssignTo may a pointer to an internal value but it must never
// mutate that value. e.g. If Get returns a []byte Value must never change the contents of the []byte.
AssignTo(dst interface{}) error
}
// TypeValue is a Value where instances can represent different PostgreSQL types. This can be useful for
// representing types such as enums, composites, and arrays.
//
// In general, instances of TypeValue should not be used to directly represent a value. It should only be used as an
// encoder and decoder internal to ConnInfo.
type TypeValue interface {
Value
// NewTypeValue creates a TypeValue including references to internal type information. e.g. the list of members
// in an EnumType.
NewTypeValue() Value
// TypeName returns the PostgreSQL name of this type.
TypeName() string
}
// ValueTranscoder is a value that implements the text and binary encoding and decoding interfaces.
type ValueTranscoder interface {
Value
TextEncoder
BinaryEncoder
TextDecoder
BinaryDecoder
}
// ResultFormatPreferrer allows a type to specify its preferred result format instead of it being inferred from
// whether it is also a BinaryDecoder.
type ResultFormatPreferrer interface {
PreferredResultFormat() int16
}
// ParamFormatPreferrer allows a type to specify its preferred param format instead of it being inferred from
// whether it is also a BinaryEncoder.
type ParamFormatPreferrer interface {
PreferredParamFormat() int16
}
type BinaryDecoder interface {
// DecodeBinary decodes src into BinaryDecoder. If src is nil then the
// original SQL value is NULL. BinaryDecoder takes ownership of src. The
// caller MUST not use it again.
DecodeBinary(ci *ConnInfo, src []byte) error
}
type TextDecoder interface {
// DecodeText decodes src into TextDecoder. If src is nil then the original
// SQL value is NULL. TextDecoder takes ownership of src. The caller MUST not
// use it again.
DecodeText(ci *ConnInfo, src []byte) error
}
// BinaryEncoder is implemented by types that can encode themselves into the
// PostgreSQL binary wire format.
type BinaryEncoder interface {
// EncodeBinary should append the binary format of self to buf. If self is the
// SQL value NULL then append nothing and return (nil, nil). The caller of
// EncodeBinary is responsible for writing the correct NULL value or the
// length of the data written.
EncodeBinary(ci *ConnInfo, buf []byte) (newBuf []byte, err error)
}
// TextEncoder is implemented by types that can encode themselves into the
// PostgreSQL text wire format.
type TextEncoder interface {
// EncodeText should append the text format of self to buf. If self is the
// SQL value NULL then append nothing and return (nil, nil). The caller of
// EncodeText is responsible for writing the correct NULL value or the
// length of the data written.
EncodeText(ci *ConnInfo, buf []byte) (newBuf []byte, err error)
}
var errUndefined = errors.New("cannot encode status undefined")
var errBadStatus = errors.New("invalid status")
type nullAssignmentError struct {
dst interface{}
}
func (e *nullAssignmentError) Error() string {
return fmt.Sprintf("cannot assign NULL to %T", e.dst)
}
type DataType struct {
Value Value
textDecoder TextDecoder
binaryDecoder BinaryDecoder
Name string
OID uint32
}
type ConnInfo struct {
oidToDataType map[uint32]*DataType
nameToDataType map[string]*DataType
reflectTypeToName map[reflect.Type]string
oidToParamFormatCode map[uint32]int16
oidToResultFormatCode map[uint32]int16
reflectTypeToDataType map[reflect.Type]*DataType
}
func newConnInfo() *ConnInfo {
return &ConnInfo{
oidToDataType: make(map[uint32]*DataType),
nameToDataType: make(map[string]*DataType),
reflectTypeToName: make(map[reflect.Type]string),
oidToParamFormatCode: make(map[uint32]int16),
oidToResultFormatCode: make(map[uint32]int16),
}
}
func NewConnInfo() *ConnInfo {
ci := newConnInfo()
ci.RegisterDataType(DataType{Value: &ACLItemArray{}, Name: "_aclitem", OID: ACLItemArrayOID})
ci.RegisterDataType(DataType{Value: &BoolArray{}, Name: "_bool", OID: BoolArrayOID})
ci.RegisterDataType(DataType{Value: &BPCharArray{}, Name: "_bpchar", OID: BPCharArrayOID})
ci.RegisterDataType(DataType{Value: &ByteaArray{}, Name: "_bytea", OID: ByteaArrayOID})
ci.RegisterDataType(DataType{Value: &CIDRArray{}, Name: "_cidr", OID: CIDRArrayOID})
ci.RegisterDataType(DataType{Value: &DateArray{}, Name: "_date", OID: DateArrayOID})
ci.RegisterDataType(DataType{Value: &Float4Array{}, Name: "_float4", OID: Float4ArrayOID})
ci.RegisterDataType(DataType{Value: &Float8Array{}, Name: "_float8", OID: Float8ArrayOID})
ci.RegisterDataType(DataType{Value: &InetArray{}, Name: "_inet", OID: InetArrayOID})
ci.RegisterDataType(DataType{Value: &Int2Array{}, Name: "_int2", OID: Int2ArrayOID})
ci.RegisterDataType(DataType{Value: &Int4Array{}, Name: "_int4", OID: Int4ArrayOID})
ci.RegisterDataType(DataType{Value: &Int8Array{}, Name: "_int8", OID: Int8ArrayOID})
ci.RegisterDataType(DataType{Value: &NumericArray{}, Name: "_numeric", OID: NumericArrayOID})
ci.RegisterDataType(DataType{Value: &TextArray{}, Name: "_text", OID: TextArrayOID})
ci.RegisterDataType(DataType{Value: &TimestampArray{}, Name: "_timestamp", OID: TimestampArrayOID})
ci.RegisterDataType(DataType{Value: &TimestamptzArray{}, Name: "_timestamptz", OID: TimestamptzArrayOID})
ci.RegisterDataType(DataType{Value: &UUIDArray{}, Name: "_uuid", OID: UUIDArrayOID})
ci.RegisterDataType(DataType{Value: &VarcharArray{}, Name: "_varchar", OID: VarcharArrayOID})
ci.RegisterDataType(DataType{Value: &ACLItem{}, Name: "aclitem", OID: ACLItemOID})
ci.RegisterDataType(DataType{Value: &Bit{}, Name: "bit", OID: BitOID})
ci.RegisterDataType(DataType{Value: &Bool{}, Name: "bool", OID: BoolOID})
ci.RegisterDataType(DataType{Value: &Box{}, Name: "box", OID: BoxOID})
ci.RegisterDataType(DataType{Value: &BPChar{}, Name: "bpchar", OID: BPCharOID})
ci.RegisterDataType(DataType{Value: &Bytea{}, Name: "bytea", OID: ByteaOID})
ci.RegisterDataType(DataType{Value: &QChar{}, Name: "char", OID: QCharOID})
ci.RegisterDataType(DataType{Value: &CID{}, Name: "cid", OID: CIDOID})
ci.RegisterDataType(DataType{Value: &CIDR{}, Name: "cidr", OID: CIDROID})
ci.RegisterDataType(DataType{Value: &Circle{}, Name: "circle", OID: CircleOID})
ci.RegisterDataType(DataType{Value: &Date{}, Name: "date", OID: DateOID})
ci.RegisterDataType(DataType{Value: &Daterange{}, Name: "daterange", OID: DaterangeOID})
ci.RegisterDataType(DataType{Value: &Float4{}, Name: "float4", OID: Float4OID})
ci.RegisterDataType(DataType{Value: &Float8{}, Name: "float8", OID: Float8OID})
ci.RegisterDataType(DataType{Value: &Inet{}, Name: "inet", OID: InetOID})
ci.RegisterDataType(DataType{Value: &Int2{}, Name: "int2", OID: Int2OID})
ci.RegisterDataType(DataType{Value: &Int4{}, Name: "int4", OID: Int4OID})
ci.RegisterDataType(DataType{Value: &Int4range{}, Name: "int4range", OID: Int4rangeOID})
ci.RegisterDataType(DataType{Value: &Int4multirange{}, Name: "int4multirange", OID: Int4multirangeOID})
ci.RegisterDataType(DataType{Value: &Int8{}, Name: "int8", OID: Int8OID})
ci.RegisterDataType(DataType{Value: &Int8range{}, Name: "int8range", OID: Int8rangeOID})
ci.RegisterDataType(DataType{Value: &Int8multirange{}, Name: "int8multirange", OID: Int8multirangeOID})
ci.RegisterDataType(DataType{Value: &Interval{}, Name: "interval", OID: IntervalOID})
ci.RegisterDataType(DataType{Value: &JSON{}, Name: "json", OID: JSONOID})
ci.RegisterDataType(DataType{Value: &JSONArray{}, Name: "_json", OID: JSONArrayOID})
ci.RegisterDataType(DataType{Value: &JSONB{}, Name: "jsonb", OID: JSONBOID})
ci.RegisterDataType(DataType{Value: &JSONBArray{}, Name: "_jsonb", OID: JSONBArrayOID})
ci.RegisterDataType(DataType{Value: &Line{}, Name: "line", OID: LineOID})
ci.RegisterDataType(DataType{Value: &Lseg{}, Name: "lseg", OID: LsegOID})
ci.RegisterDataType(DataType{Value: &Macaddr{}, Name: "macaddr", OID: MacaddrOID})
ci.RegisterDataType(DataType{Value: &Name{}, Name: "name", OID: NameOID})
ci.RegisterDataType(DataType{Value: &Numeric{}, Name: "numeric", OID: NumericOID})
ci.RegisterDataType(DataType{Value: &Numrange{}, Name: "numrange", OID: NumrangeOID})
ci.RegisterDataType(DataType{Value: &Nummultirange{}, Name: "nummultirange", OID: NummultirangeOID})
ci.RegisterDataType(DataType{Value: &OIDValue{}, Name: "oid", OID: OIDOID})
ci.RegisterDataType(DataType{Value: &Path{}, Name: "path", OID: PathOID})
ci.RegisterDataType(DataType{Value: &Point{}, Name: "point", OID: PointOID})
ci.RegisterDataType(DataType{Value: &Polygon{}, Name: "polygon", OID: PolygonOID})
ci.RegisterDataType(DataType{Value: &Record{}, Name: "record", OID: RecordOID})
ci.RegisterDataType(DataType{Value: &Text{}, Name: "text", OID: TextOID})
ci.RegisterDataType(DataType{Value: &TID{}, Name: "tid", OID: TIDOID})
ci.RegisterDataType(DataType{Value: &Time{}, Name: "time", OID: TimeOID})
ci.RegisterDataType(DataType{Value: &Timestamp{}, Name: "timestamp", OID: TimestampOID})
ci.RegisterDataType(DataType{Value: &Timestamptz{}, Name: "timestamptz", OID: TimestamptzOID})
ci.RegisterDataType(DataType{Value: &Tsrange{}, Name: "tsrange", OID: TsrangeOID})
ci.RegisterDataType(DataType{Value: &TsrangeArray{}, Name: "_tsrange", OID: TsrangeArrayOID})
ci.RegisterDataType(DataType{Value: &Tstzrange{}, Name: "tstzrange", OID: TstzrangeOID})
ci.RegisterDataType(DataType{Value: &TstzrangeArray{}, Name: "_tstzrange", OID: TstzrangeArrayOID})
ci.RegisterDataType(DataType{Value: &Unknown{}, Name: "unknown", OID: UnknownOID})
ci.RegisterDataType(DataType{Value: &UUID{}, Name: "uuid", OID: UUIDOID})
ci.RegisterDataType(DataType{Value: &Varbit{}, Name: "varbit", OID: VarbitOID})
ci.RegisterDataType(DataType{Value: &Varchar{}, Name: "varchar", OID: VarcharOID})
ci.RegisterDataType(DataType{Value: &XID{}, Name: "xid", OID: XIDOID})
registerDefaultPgTypeVariants := func(name, arrayName string, value interface{}) {
ci.RegisterDefaultPgType(value, name)
valueType := reflect.TypeOf(value)
ci.RegisterDefaultPgType(reflect.New(valueType).Interface(), name)
sliceType := reflect.SliceOf(valueType)
ci.RegisterDefaultPgType(reflect.MakeSlice(sliceType, 0, 0).Interface(), arrayName)
ci.RegisterDefaultPgType(reflect.New(sliceType).Interface(), arrayName)
}
// Integer types that directly map to a PostgreSQL type
registerDefaultPgTypeVariants("int2", "_int2", int16(0))
registerDefaultPgTypeVariants("int4", "_int4", int32(0))
registerDefaultPgTypeVariants("int8", "_int8", int64(0))
// Integer types that do not have a direct match to a PostgreSQL type
registerDefaultPgTypeVariants("int8", "_int8", uint16(0))
registerDefaultPgTypeVariants("int8", "_int8", uint32(0))
registerDefaultPgTypeVariants("int8", "_int8", uint64(0))
registerDefaultPgTypeVariants("int8", "_int8", int(0))
registerDefaultPgTypeVariants("int8", "_int8", uint(0))
registerDefaultPgTypeVariants("float4", "_float4", float32(0))
registerDefaultPgTypeVariants("float8", "_float8", float64(0))
registerDefaultPgTypeVariants("bool", "_bool", false)
registerDefaultPgTypeVariants("timestamptz", "_timestamptz", time.Time{})
registerDefaultPgTypeVariants("text", "_text", "")
registerDefaultPgTypeVariants("bytea", "_bytea", []byte(nil))
registerDefaultPgTypeVariants("inet", "_inet", net.IP{})
ci.RegisterDefaultPgType((*net.IPNet)(nil), "cidr")
ci.RegisterDefaultPgType([]*net.IPNet(nil), "_cidr")
return ci
}
func (ci *ConnInfo) InitializeDataTypes(nameOIDs map[string]uint32) {
for name, oid := range nameOIDs {
var value Value
if t, ok := nameValues[name]; ok {
value = reflect.New(reflect.ValueOf(t).Elem().Type()).Interface().(Value)
} else {
value = &GenericText{}
}
ci.RegisterDataType(DataType{Value: value, Name: name, OID: oid})
}
}
func (ci *ConnInfo) RegisterDataType(t DataType) {
t.Value = NewValue(t.Value)
ci.oidToDataType[t.OID] = &t
ci.nameToDataType[t.Name] = &t
{
var formatCode int16
if pfp, ok := t.Value.(ParamFormatPreferrer); ok {
formatCode = pfp.PreferredParamFormat()
} else if _, ok := t.Value.(BinaryEncoder); ok {
formatCode = BinaryFormatCode
}
ci.oidToParamFormatCode[t.OID] = formatCode
}
{
var formatCode int16
if rfp, ok := t.Value.(ResultFormatPreferrer); ok {
formatCode = rfp.PreferredResultFormat()
} else if _, ok := t.Value.(BinaryDecoder); ok {
formatCode = BinaryFormatCode
}
ci.oidToResultFormatCode[t.OID] = formatCode
}
if d, ok := t.Value.(TextDecoder); ok {
t.textDecoder = d
}
if d, ok := t.Value.(BinaryDecoder); ok {
t.binaryDecoder = d
}
ci.reflectTypeToDataType = nil // Invalidated by type registration
}
// RegisterDefaultPgType registers a mapping of a Go type to a PostgreSQL type name. Typically the data type to be
// encoded or decoded is determined by the PostgreSQL OID. But if the OID of a value to be encoded or decoded is
// unknown, this additional mapping will be used by DataTypeForValue to determine a suitable data type.
func (ci *ConnInfo) RegisterDefaultPgType(value interface{}, name string) {
ci.reflectTypeToName[reflect.TypeOf(value)] = name
ci.reflectTypeToDataType = nil // Invalidated by registering a default type
}
func (ci *ConnInfo) DataTypeForOID(oid uint32) (*DataType, bool) {
dt, ok := ci.oidToDataType[oid]
return dt, ok
}
func (ci *ConnInfo) DataTypeForName(name string) (*DataType, bool) {
dt, ok := ci.nameToDataType[name]
return dt, ok
}
func (ci *ConnInfo) buildReflectTypeToDataType() {
ci.reflectTypeToDataType = make(map[reflect.Type]*DataType)
for _, dt := range ci.oidToDataType {
if _, is := dt.Value.(TypeValue); !is {
ci.reflectTypeToDataType[reflect.ValueOf(dt.Value).Type()] = dt
}
}
for reflectType, name := range ci.reflectTypeToName {
if dt, ok := ci.nameToDataType[name]; ok {
ci.reflectTypeToDataType[reflectType] = dt
}
}
}
// DataTypeForValue finds a data type suitable for v. Use RegisterDataType to register types that can encode and decode
// themselves. Use RegisterDefaultPgType to register that can be handled by a registered data type.
func (ci *ConnInfo) DataTypeForValue(v interface{}) (*DataType, bool) {
if ci.reflectTypeToDataType == nil {
ci.buildReflectTypeToDataType()
}
if tv, ok := v.(TypeValue); ok {
dt, ok := ci.nameToDataType[tv.TypeName()]
return dt, ok
}
dt, ok := ci.reflectTypeToDataType[reflect.TypeOf(v)]
return dt, ok
}
func (ci *ConnInfo) ParamFormatCodeForOID(oid uint32) int16 {
fc, ok := ci.oidToParamFormatCode[oid]
if ok {
return fc
}
return TextFormatCode
}
func (ci *ConnInfo) ResultFormatCodeForOID(oid uint32) int16 {
fc, ok := ci.oidToResultFormatCode[oid]
if ok {
return fc
}
return TextFormatCode
}
// DeepCopy makes a deep copy of the ConnInfo.
func (ci *ConnInfo) DeepCopy() *ConnInfo {
ci2 := newConnInfo()
for _, dt := range ci.oidToDataType {
ci2.RegisterDataType(DataType{
Value: NewValue(dt.Value),
Name: dt.Name,
OID: dt.OID,
})
}
for t, n := range ci.reflectTypeToName {
ci2.reflectTypeToName[t] = n
}
return ci2
}
// ScanPlan is a precompiled plan to scan into a type of destination.
type ScanPlan interface {
// Scan scans src into dst. If the dst type has changed in an incompatible way a ScanPlan should automatically
// replan and scan.
Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error
}
type scanPlanDstBinaryDecoder struct{}
func (scanPlanDstBinaryDecoder) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error {
if d, ok := (dst).(BinaryDecoder); ok {
return d.DecodeBinary(ci, src)
}
newPlan := ci.PlanScan(oid, formatCode, dst)
return newPlan.Scan(ci, oid, formatCode, src, dst)
}
type scanPlanDstTextDecoder struct{}
func (plan scanPlanDstTextDecoder) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error {
if d, ok := (dst).(TextDecoder); ok {
return d.DecodeText(ci, src)
}
newPlan := ci.PlanScan(oid, formatCode, dst)
return newPlan.Scan(ci, oid, formatCode, src, dst)
}
type scanPlanDataTypeSQLScanner DataType
func (plan *scanPlanDataTypeSQLScanner) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error {
scanner, ok := dst.(sql.Scanner)
if !ok {
dv := reflect.ValueOf(dst)
if dv.Kind() != reflect.Ptr || !dv.Type().Elem().Implements(scannerType) {
newPlan := ci.PlanScan(oid, formatCode, dst)
return newPlan.Scan(ci, oid, formatCode, src, dst)
}
if src == nil {
// Ensure the pointer points to a zero version of the value
dv.Elem().Set(reflect.Zero(dv.Type().Elem()))
return nil
}
dv = dv.Elem()
// If the pointer is to a nil pointer then set that before scanning
if dv.Kind() == reflect.Ptr && dv.IsNil() {
dv.Set(reflect.New(dv.Type().Elem()))
}
scanner = dv.Interface().(sql.Scanner)
}
dt := (*DataType)(plan)
var err error
switch formatCode {
case BinaryFormatCode:
err = dt.binaryDecoder.DecodeBinary(ci, src)
case TextFormatCode:
err = dt.textDecoder.DecodeText(ci, src)
}
if err != nil {
return err
}
sqlSrc, err := DatabaseSQLValue(ci, dt.Value)
if err != nil {
return err
}
return scanner.Scan(sqlSrc)
}
type scanPlanDataTypeAssignTo DataType
func (plan *scanPlanDataTypeAssignTo) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error {
dt := (*DataType)(plan)
var err error
switch formatCode {
case BinaryFormatCode:
err = dt.binaryDecoder.DecodeBinary(ci, src)
case TextFormatCode:
err = dt.textDecoder.DecodeText(ci, src)
}
if err != nil {
return err
}
assignToErr := dt.Value.AssignTo(dst)
if assignToErr == nil {
return nil
}
if dstPtr, ok := dst.(*interface{}); ok {
*dstPtr = dt.Value.Get()
return nil
}
// assignToErr might have failed because the type of destination has changed
newPlan := ci.PlanScan(oid, formatCode, dst)
if newPlan, sameType := newPlan.(*scanPlanDataTypeAssignTo); !sameType {
return newPlan.Scan(ci, oid, formatCode, src, dst)
}
return assignToErr
}
type scanPlanSQLScanner struct{}
func (scanPlanSQLScanner) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error {
scanner, ok := dst.(sql.Scanner)
if !ok {
dv := reflect.ValueOf(dst)
if dv.Kind() != reflect.Ptr || !dv.Type().Elem().Implements(scannerType) {
newPlan := ci.PlanScan(oid, formatCode, dst)
return newPlan.Scan(ci, oid, formatCode, src, dst)
}
if src == nil {
// Ensure the pointer points to a zero version of the value
dv.Elem().Set(reflect.Zero(dv.Type()))
return nil
}
dv = dv.Elem()
// If the pointer is to a nil pointer then set that before scanning
if dv.Kind() == reflect.Ptr && dv.IsNil() {
dv.Set(reflect.New(dv.Type().Elem()))
}
scanner = dv.Interface().(sql.Scanner)
}
if src == nil {
// This is necessary because interface value []byte:nil does not equal nil:nil for the binary format path and the
// text format path would be converted to empty string.
return scanner.Scan(nil)
} else if formatCode == BinaryFormatCode {
return scanner.Scan(src)
} else {
return scanner.Scan(string(src))
}
}
type scanPlanReflection struct{}
func (scanPlanReflection) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error {
// We might be given a pointer to something that implements the decoder interface(s),
// even though the pointer itself doesn't.
refVal := reflect.ValueOf(dst)
if refVal.Kind() == reflect.Ptr && refVal.Type().Elem().Kind() == reflect.Ptr {
// If the database returned NULL, then we set dest as nil to indicate that.
if src == nil {
nilPtr := reflect.Zero(refVal.Type().Elem())
refVal.Elem().Set(nilPtr)
return nil
}
// We need to allocate an element, and set the destination to it
// Then we can retry as that element.
elemPtr := reflect.New(refVal.Type().Elem().Elem())
refVal.Elem().Set(elemPtr)
plan := ci.PlanScan(oid, formatCode, elemPtr.Interface())
return plan.Scan(ci, oid, formatCode, src, elemPtr.Interface())
}
return scanUnknownType(oid, formatCode, src, dst)
}
type scanPlanBinaryInt16 struct{}
func (scanPlanBinaryInt16) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error {
if src == nil {
return fmt.Errorf("cannot scan null into %T", dst)
}
if len(src) != 2 {
return fmt.Errorf("invalid length for int2: %v", len(src))
}
if p, ok := (dst).(*int16); ok {
*p = int16(binary.BigEndian.Uint16(src))
return nil
}
newPlan := ci.PlanScan(oid, formatCode, dst)
return newPlan.Scan(ci, oid, formatCode, src, dst)
}
type scanPlanBinaryInt32 struct{}
func (scanPlanBinaryInt32) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error {
if src == nil {
return fmt.Errorf("cannot scan null into %T", dst)
}
if len(src) != 4 {
return fmt.Errorf("invalid length for int4: %v", len(src))
}
if p, ok := (dst).(*int32); ok {
*p = int32(binary.BigEndian.Uint32(src))
return nil
}
newPlan := ci.PlanScan(oid, formatCode, dst)
return newPlan.Scan(ci, oid, formatCode, src, dst)
}
type scanPlanBinaryInt64 struct{}
func (scanPlanBinaryInt64) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error {
if src == nil {
return fmt.Errorf("cannot scan null into %T", dst)
}
if len(src) != 8 {
return fmt.Errorf("invalid length for int8: %v", len(src))
}
if p, ok := (dst).(*int64); ok {
*p = int64(binary.BigEndian.Uint64(src))
return nil
}
newPlan := ci.PlanScan(oid, formatCode, dst)
return newPlan.Scan(ci, oid, formatCode, src, dst)
}
type scanPlanBinaryFloat32 struct{}
func (scanPlanBinaryFloat32) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error {
if src == nil {
return fmt.Errorf("cannot scan null into %T", dst)
}
if len(src) != 4 {
return fmt.Errorf("invalid length for int4: %v", len(src))
}
if p, ok := (dst).(*float32); ok {
n := int32(binary.BigEndian.Uint32(src))
*p = float32(math.Float32frombits(uint32(n)))
return nil
}
newPlan := ci.PlanScan(oid, formatCode, dst)
return newPlan.Scan(ci, oid, formatCode, src, dst)
}
type scanPlanBinaryFloat64 struct{}
func (scanPlanBinaryFloat64) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error {
if src == nil {
return fmt.Errorf("cannot scan null into %T", dst)
}
if len(src) != 8 {
return fmt.Errorf("invalid length for int8: %v", len(src))
}
if p, ok := (dst).(*float64); ok {
n := int64(binary.BigEndian.Uint64(src))
*p = float64(math.Float64frombits(uint64(n)))
return nil
}
newPlan := ci.PlanScan(oid, formatCode, dst)
return newPlan.Scan(ci, oid, formatCode, src, dst)
}
type scanPlanBinaryBytes struct{}
func (scanPlanBinaryBytes) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error {
if p, ok := (dst).(*[]byte); ok {
*p = src
return nil
}
newPlan := ci.PlanScan(oid, formatCode, dst)
return newPlan.Scan(ci, oid, formatCode, src, dst)
}
type scanPlanString struct{}
func (scanPlanString) Scan(ci *ConnInfo, oid uint32, formatCode int16, src []byte, dst interface{}) error {
if src == nil {
return fmt.Errorf("cannot scan null into %T", dst)
}
if p, ok := (dst).(*string); ok {
*p = string(src)
return nil
}
newPlan := ci.PlanScan(oid, formatCode, dst)
return newPlan.Scan(ci, oid, formatCode, src, dst)
}
var scannerType = reflect.TypeOf((*sql.Scanner)(nil)).Elem()
func isScanner(dst interface{}) bool {
if _, ok := dst.(sql.Scanner); ok {
return true
}
if t := reflect.TypeOf(dst); t != nil && t.Kind() == reflect.Ptr && t.Elem().Implements(scannerType) {
return true
}
return false
}
// PlanScan prepares a plan to scan a value into dst.
func (ci *ConnInfo) PlanScan(oid uint32, formatCode int16, dst interface{}) ScanPlan {
switch formatCode {
case BinaryFormatCode:
switch dst.(type) {
case *string:
switch oid {
case TextOID, VarcharOID:
return scanPlanString{}
}
case *int16:
if oid == Int2OID {
return scanPlanBinaryInt16{}
}
case *int32:
if oid == Int4OID {
return scanPlanBinaryInt32{}
}
case *int64:
if oid == Int8OID {
return scanPlanBinaryInt64{}
}
case *float32:
if oid == Float4OID {
return scanPlanBinaryFloat32{}
}
case *float64:
if oid == Float8OID {
return scanPlanBinaryFloat64{}
}
case *[]byte:
switch oid {
case ByteaOID, TextOID, VarcharOID, JSONOID:
return scanPlanBinaryBytes{}
}
case BinaryDecoder:
return scanPlanDstBinaryDecoder{}
}
case TextFormatCode:
switch dst.(type) {
case *string:
return scanPlanString{}
case *[]byte:
if oid != ByteaOID {
return scanPlanBinaryBytes{}
}
case TextDecoder:
return scanPlanDstTextDecoder{}
}
}
var dt *DataType
if oid == 0 {
if dataType, ok := ci.DataTypeForValue(dst); ok {
dt = dataType
}
} else {
if dataType, ok := ci.DataTypeForOID(oid); ok {
dt = dataType
}
}
if dt != nil {
if isScanner(dst) {
return (*scanPlanDataTypeSQLScanner)(dt)
}
return (*scanPlanDataTypeAssignTo)(dt)
}
if isScanner(dst) {
return scanPlanSQLScanner{}
}
return scanPlanReflection{}
}
func (ci *ConnInfo) Scan(oid uint32, formatCode int16, src []byte, dst interface{}) error {
if dst == nil {
return nil
}
plan := ci.PlanScan(oid, formatCode, dst)
return plan.Scan(ci, oid, formatCode, src, dst)
}
func scanUnknownType(oid uint32, formatCode int16, buf []byte, dest interface{}) error {
switch dest := dest.(type) {
case *string:
if formatCode == BinaryFormatCode {
return fmt.Errorf("unknown oid %d in binary format cannot be scanned into %T", oid, dest)
}
*dest = string(buf)
return nil
case *[]byte:
*dest = buf
return nil
default:
if nextDst, retry := GetAssignToDstType(dest); retry {
return scanUnknownType(oid, formatCode, buf, nextDst)
}
return fmt.Errorf("unknown oid %d cannot be scanned into %T", oid, dest)
}
}
// NewValue returns a new instance of the same type as v.
func NewValue(v Value) Value {
if tv, ok := v.(TypeValue); ok {
return tv.NewTypeValue()
} else {
return reflect.New(reflect.ValueOf(v).Elem().Type()).Interface().(Value)
}
}
var nameValues map[string]Value
func init() {
nameValues = map[string]Value{
"_aclitem": &ACLItemArray{},
"_bool": &BoolArray{},
"_bpchar": &BPCharArray{},
"_bytea": &ByteaArray{},
"_cidr": &CIDRArray{},
"_date": &DateArray{},
"_float4": &Float4Array{},
"_float8": &Float8Array{},
"_inet": &InetArray{},
"_int2": &Int2Array{},
"_int4": &Int4Array{},
"_int8": &Int8Array{},
"_numeric": &NumericArray{},
"_text": &TextArray{},
"_timestamp": &TimestampArray{},
"_timestamptz": &TimestamptzArray{},
"_uuid": &UUIDArray{},
"_varchar": &VarcharArray{},
"_json": &JSONArray{},
"_jsonb": &JSONBArray{},
"aclitem": &ACLItem{},
"bit": &Bit{},
"bool": &Bool{},
"box": &Box{},
"bpchar": &BPChar{},
"bytea": &Bytea{},
"char": &QChar{},
"cid": &CID{},
"cidr": &CIDR{},
"circle": &Circle{},
"date": &Date{},
"daterange": &Daterange{},
"float4": &Float4{},
"float8": &Float8{},
"hstore": &Hstore{},
"inet": &Inet{},
"int2": &Int2{},
"int4": &Int4{},
"int4range": &Int4range{},
"int4multirange": &Int4multirange{},
"int8": &Int8{},
"int8range": &Int8range{},
"int8multirange": &Int8multirange{},
"interval": &Interval{},
"json": &JSON{},
"jsonb": &JSONB{},
"line": &Line{},
"lseg": &Lseg{},
"macaddr": &Macaddr{},
"name": &Name{},
"numeric": &Numeric{},
"numrange": &Numrange{},
"nummultirange": &Nummultirange{},
"oid": &OIDValue{},
"path": &Path{},
"point": &Point{},
"polygon": &Polygon{},
"record": &Record{},
"text": &Text{},
"tid": &TID{},
"timestamp": &Timestamp{},
"timestamptz": &Timestamptz{},
"tsrange": &Tsrange{},
"_tsrange": &TsrangeArray{},
"tstzrange": &Tstzrange{},
"_tstzrange": &TstzrangeArray{},
"unknown": &Unknown{},
"uuid": &UUID{},
"varbit": &Varbit{},
"varchar": &Varchar{},
"xid": &XID{},
}
}
-162
View File
@@ -1,162 +0,0 @@
package pgtype
import (
"database/sql/driver"
"encoding/binary"
"fmt"
"math"
"strconv"
"github.com/jackc/pgio"
)
// pguint32 is the core type that is used to implement PostgreSQL types such as
// CID and XID.
type pguint32 struct {
Uint uint32
Status Status
}
// Set converts from src to dst. Note that as pguint32 is not a general
// number type Set does not do automatic type conversion as other number
// types do.
func (dst *pguint32) Set(src interface{}) error {
switch value := src.(type) {
case int64:
if value < 0 {
return fmt.Errorf("%d is less than minimum value for pguint32", value)
}
if value > math.MaxUint32 {
return fmt.Errorf("%d is greater than maximum value for pguint32", value)
}
*dst = pguint32{Uint: uint32(value), Status: Present}
case uint32:
*dst = pguint32{Uint: value, Status: Present}
default:
return fmt.Errorf("cannot convert %v to pguint32", value)
}
return nil
}
func (dst pguint32) Get() interface{} {
switch dst.Status {
case Present:
return dst.Uint
case Null:
return nil
default:
return dst.Status
}
}
// AssignTo assigns from src to dst. Note that as pguint32 is not a general number
// type AssignTo does not do automatic type conversion as other number types do.
func (src *pguint32) AssignTo(dst interface{}) error {
switch v := dst.(type) {
case *uint32:
if src.Status == Present {
*v = src.Uint
} else {
return fmt.Errorf("cannot assign %v into %T", src, dst)
}
case **uint32:
if src.Status == Present {
n := src.Uint
*v = &n
} else {
*v = nil
}
}
return nil
}
func (dst *pguint32) DecodeText(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = pguint32{Status: Null}
return nil
}
n, err := strconv.ParseUint(string(src), 10, 32)
if err != nil {
return err
}
*dst = pguint32{Uint: uint32(n), Status: Present}
return nil
}
func (dst *pguint32) DecodeBinary(ci *ConnInfo, src []byte) error {
if src == nil {
*dst = pguint32{Status: Null}
return nil
}
if len(src) != 4 {
return fmt.Errorf("invalid length: %v", len(src))
}
n := binary.BigEndian.Uint32(src)
*dst = pguint32{Uint: n, Status: Present}
return nil
}
func (src pguint32) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
return append(buf, strconv.FormatUint(uint64(src.Uint), 10)...), nil
}
func (src pguint32) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
switch src.Status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
return pgio.AppendUint32(buf, src.Uint), nil
}
// Scan implements the database/sql Scanner interface.
func (dst *pguint32) Scan(src interface{}) error {
if src == nil {
*dst = pguint32{Status: Null}
return nil
}
switch src := src.(type) {
case uint32:
*dst = pguint32{Uint: src, Status: Present}
return nil
case int64:
*dst = pguint32{Uint: uint32(src), Status: Present}
return nil
case string:
return dst.DecodeText(nil, []byte(src))
case []byte:
srcCopy := make([]byte, len(src))
copy(srcCopy, src)
return dst.DecodeText(nil, srcCopy)
}
return fmt.Errorf("cannot scan %T", src)
}
// Value implements the database/sql/driver Valuer interface.
func (src pguint32) Value() (driver.Value, error) {
switch src.Status {
case Present:
return int64(src.Uint), nil
case Null:
return nil, nil
default:
return nil, errUndefined
}
}
Loaded 100 of 360 files, more files were not shown because too many files have changed in this diff. Show more