PostgreSQL 의존성 및 내부 유틸리티 추가:
Some checks failed
Build Push and Restart Compose / deploy (push) Failing after 1m47s
Some checks failed
Build Push and Restart Compose / deploy (push) Failing after 1m47s
- `github.com/lib/pq` PostgreSQL 드라이버 vendor 디렉토리에 추가. - PostgreSQL 관련 내부 패키지(`pqsql`, `proto`, `pqtime`, `pgpass`, `pgservice`, `pqutil`) 구현: - SQL 어휘 처리, 프로토콜 상수 및 구조 정의, 시간 파서/포맷터(`Parse`, `Format`). - `.pgpass` 파일 및 `pg_service.conf` 관리 기능 추가. - 파일/사용자 권한 검증 및 플랫폼별 사용자 정보 조회 기능 포함. - 데이터베이스 초기화 로직 추가 (`services/db.go`): - PostgreSQL 연결 설정 및 초기 스키마 생성. - 자동매매 관련 DB 레포지토리(`services/autotrade_repo.go`) 구현: - 자동매매 규칙 및 포지션 관리 로직 추가 (`dbInsertRule`, `dbLoadRules` 등).
This commit is contained in:
70
vendor/github.com/lib/pq/internal/pgpass/pgpass.go
generated
vendored
Normal file
70
vendor/github.com/lib/pq/internal/pgpass/pgpass.go
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
package pgpass
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/lib/pq/internal/pqutil"
|
||||
)
|
||||
|
||||
func PasswordFromPgpass(passfile, user, password, host, port, dbname string) string {
|
||||
if password != "" { // Do not process .pgpass if a password was supplied.
|
||||
return password
|
||||
}
|
||||
|
||||
filename := pqutil.Pgpass(passfile)
|
||||
if filename == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
fp, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
defer fp.Close()
|
||||
|
||||
scan := bufio.NewScanner(fp)
|
||||
for scan.Scan() {
|
||||
line := scan.Text()
|
||||
if len(line) == 0 || line[0] == '#' {
|
||||
continue
|
||||
}
|
||||
split := splitFields(line)
|
||||
if len(split) != 5 {
|
||||
continue
|
||||
}
|
||||
|
||||
socket := host == "" || filepath.IsAbs(host) || strings.HasPrefix(host, "@")
|
||||
if (split[0] == "*" || split[0] == host || (split[0] == "localhost" && socket)) &&
|
||||
(split[1] == "*" || split[1] == port) &&
|
||||
(split[2] == "*" || split[2] == dbname) &&
|
||||
(split[3] == "*" || split[3] == user) {
|
||||
return split[4]
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func splitFields(s string) []string {
|
||||
var (
|
||||
fs = make([]string, 0, 5)
|
||||
f = make([]rune, 0, len(s))
|
||||
esc bool
|
||||
)
|
||||
for _, c := range s {
|
||||
switch {
|
||||
case esc:
|
||||
f, esc = append(f, c), false
|
||||
case c == '\\':
|
||||
esc = true
|
||||
case c == ':':
|
||||
fs, f = append(fs, string(f)), f[:0]
|
||||
default:
|
||||
f = append(f, c)
|
||||
}
|
||||
}
|
||||
return append(fs, string(f))
|
||||
}
|
||||
70
vendor/github.com/lib/pq/internal/pgservice/pgservice.go
generated
vendored
Normal file
70
vendor/github.com/lib/pq/internal/pgservice/pgservice.go
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
package pgservice
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/lib/pq/internal/pqutil"
|
||||
)
|
||||
|
||||
func FindService(path string, service string) (map[string]string, error) {
|
||||
fp, err := os.Open(path)
|
||||
if err != nil {
|
||||
if pqutil.ErrNotExists(err) {
|
||||
// libpq just returns "definition of service not found" if the
|
||||
// default file doesn't exist, but IMO that's confusing.
|
||||
return nil, fmt.Errorf("service file %q not found", path)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
defer fp.Close()
|
||||
|
||||
var (
|
||||
scan = bufio.NewScanner(fp)
|
||||
i int
|
||||
)
|
||||
for scan.Scan() {
|
||||
i++
|
||||
line := strings.TrimSpace(scan.Text())
|
||||
if line == "" || line[0] == '#' {
|
||||
continue
|
||||
}
|
||||
|
||||
// [service] header that we want.
|
||||
if line[0] == '[' && line[len(line)-1] == ']' && strings.TrimSpace(line[1:len(line)-1]) == service {
|
||||
opts := make(map[string]string)
|
||||
for scan.Scan() {
|
||||
i++
|
||||
line := strings.TrimSpace(scan.Text())
|
||||
if line == "" || line[0] == '#' {
|
||||
continue
|
||||
}
|
||||
// Next header: our work here is done.
|
||||
if line[0] == '[' && line[len(line)-1] == ']' {
|
||||
return opts, nil
|
||||
}
|
||||
|
||||
k, v, ok := strings.Cut(line, "=")
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("line %d: missing '=' in %q", i, line)
|
||||
}
|
||||
k, v = strings.TrimSpace(k), strings.TrimSpace(v)
|
||||
if k == "" {
|
||||
return nil, fmt.Errorf("line %d: no value before '=' in %q", i, line)
|
||||
}
|
||||
opts[k] = v
|
||||
}
|
||||
if scan.Err() != nil {
|
||||
return nil, scan.Err()
|
||||
}
|
||||
return opts, nil
|
||||
}
|
||||
}
|
||||
if scan.Err() != nil {
|
||||
return nil, scan.Err()
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("definition of service %q not found", service)
|
||||
}
|
||||
37
vendor/github.com/lib/pq/internal/pqsql/copy.go
generated
vendored
Normal file
37
vendor/github.com/lib/pq/internal/pqsql/copy.go
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
package pqsql
|
||||
|
||||
// StartsWithCopy reports if the SQL strings start with "copy", ignoring
|
||||
// whitespace, comments, and casing.
|
||||
func StartsWithCopy(query string) bool {
|
||||
if len(query) < 4 {
|
||||
return false
|
||||
}
|
||||
var linecmt, blockcmt bool
|
||||
for i := 0; i < len(query); i++ {
|
||||
c := query[i]
|
||||
if linecmt {
|
||||
linecmt = c != '\n'
|
||||
continue
|
||||
}
|
||||
if blockcmt {
|
||||
blockcmt = !(c == '/' && query[i-1] == '*')
|
||||
continue
|
||||
}
|
||||
if c == '-' && len(query) > i+1 && query[i+1] == '-' {
|
||||
linecmt = true
|
||||
continue
|
||||
}
|
||||
if c == '/' && len(query) > i+1 && query[i+1] == '*' {
|
||||
blockcmt = true
|
||||
continue
|
||||
}
|
||||
if c == ' ' || c == '\t' || c == '\r' || c == '\n' {
|
||||
continue
|
||||
}
|
||||
|
||||
// First non-comment and non-whitespace.
|
||||
return len(query) > i+3 && c|0x20 == 'c' && query[i+1]|0x20 == 'o' &&
|
||||
query[i+2]|0x20 == 'p' && query[i+3]|0x20 == 'y'
|
||||
}
|
||||
return false
|
||||
}
|
||||
37
vendor/github.com/lib/pq/internal/pqtime/loc.go
generated
vendored
Normal file
37
vendor/github.com/lib/pq/internal/pqtime/loc.go
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
package pqtime
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// The location cache caches the time zones typically used by the client.
|
||||
type locationCache struct {
|
||||
cache map[int]*time.Location
|
||||
lock sync.Mutex
|
||||
}
|
||||
|
||||
// All connections share the same list of timezones. Benchmarking shows that
|
||||
// about 5% speed could be gained by putting the cache in the connection and
|
||||
// losing the mutex, at the cost of a small amount of memory and a somewhat
|
||||
// significant increase in code complexity.
|
||||
var globalLocationCache = &locationCache{cache: make(map[int]*time.Location)}
|
||||
|
||||
func Reset() {
|
||||
globalLocationCache = &locationCache{cache: make(map[int]*time.Location)}
|
||||
}
|
||||
|
||||
// Returns the cached timezone for the specified offset, creating and caching
|
||||
// it if necessary.
|
||||
func (c *locationCache) getLocation(offset int) *time.Location {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
l, ok := c.cache[offset]
|
||||
if !ok {
|
||||
// TODO(v2): for offset=0 it should use some descriptive text like
|
||||
// "without time zone".
|
||||
l = time.FixedZone("", offset)
|
||||
c.cache[offset] = l
|
||||
}
|
||||
return l
|
||||
}
|
||||
190
vendor/github.com/lib/pq/internal/pqtime/pqtime.go
generated
vendored
Normal file
190
vendor/github.com/lib/pq/internal/pqtime/pqtime.go
generated
vendored
Normal file
@@ -0,0 +1,190 @@
|
||||
package pqtime
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var errInvalidTimestamp = errors.New("invalid timestamp")
|
||||
|
||||
type timestampParser struct {
|
||||
err error
|
||||
}
|
||||
|
||||
func (p *timestampParser) expect(str string, char byte, pos int) {
|
||||
if p.err != nil {
|
||||
return
|
||||
}
|
||||
if pos+1 > len(str) {
|
||||
p.err = errInvalidTimestamp
|
||||
return
|
||||
}
|
||||
if c := str[pos]; c != char && p.err == nil {
|
||||
p.err = fmt.Errorf("expected '%v' at position %v; got '%v'", char, pos, c)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *timestampParser) mustAtoi(str string, begin int, end int) int {
|
||||
if p.err != nil {
|
||||
return 0
|
||||
}
|
||||
if begin < 0 || end < 0 || begin > end || end > len(str) {
|
||||
p.err = errInvalidTimestamp
|
||||
return 0
|
||||
}
|
||||
result, err := strconv.Atoi(str[begin:end])
|
||||
if err != nil {
|
||||
if p.err == nil {
|
||||
p.err = fmt.Errorf("expected number; got '%v'", str)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func Parse(currentLocation *time.Location, str string) (time.Time, error) {
|
||||
p := timestampParser{}
|
||||
|
||||
monSep := strings.IndexRune(str, '-')
|
||||
// this is Gregorian year, not ISO Year
|
||||
// In Gregorian system, the year 1 BC is followed by AD 1
|
||||
year := p.mustAtoi(str, 0, monSep)
|
||||
daySep := monSep + 3
|
||||
month := p.mustAtoi(str, monSep+1, daySep)
|
||||
p.expect(str, '-', daySep)
|
||||
timeSep := daySep + 3
|
||||
day := p.mustAtoi(str, daySep+1, timeSep)
|
||||
|
||||
minLen := monSep + len("01-01") + 1
|
||||
|
||||
isBC := strings.HasSuffix(str, " BC")
|
||||
if isBC {
|
||||
minLen += 3
|
||||
}
|
||||
|
||||
var hour, minute, second int
|
||||
if len(str) > minLen {
|
||||
p.expect(str, ' ', timeSep)
|
||||
minSep := timeSep + 3
|
||||
p.expect(str, ':', minSep)
|
||||
hour = p.mustAtoi(str, timeSep+1, minSep)
|
||||
secSep := minSep + 3
|
||||
p.expect(str, ':', secSep)
|
||||
minute = p.mustAtoi(str, minSep+1, secSep)
|
||||
secEnd := secSep + 3
|
||||
second = p.mustAtoi(str, secSep+1, secEnd)
|
||||
}
|
||||
remainderIdx := monSep + len("01-01 00:00:00") + 1
|
||||
// Three optional (but ordered) sections follow: the
|
||||
// fractional seconds, the time zone offset, and the BC
|
||||
// designation. We set them up here and adjust the other
|
||||
// offsets if the preceding sections exist.
|
||||
|
||||
nanoSec := 0
|
||||
tzOff := 0
|
||||
|
||||
if remainderIdx < len(str) && str[remainderIdx] == '.' {
|
||||
fracStart := remainderIdx + 1
|
||||
fracOff := strings.IndexAny(str[fracStart:], "-+Z ")
|
||||
if fracOff < 0 {
|
||||
fracOff = len(str) - fracStart
|
||||
}
|
||||
fracSec := p.mustAtoi(str, fracStart, fracStart+fracOff)
|
||||
nanoSec = fracSec * (1000000000 / int(math.Pow(10, float64(fracOff))))
|
||||
|
||||
remainderIdx += fracOff + 1
|
||||
}
|
||||
if tzStart := remainderIdx; tzStart < len(str) && (str[tzStart] == '-' || str[tzStart] == '+') {
|
||||
// time zone separator is always '-' or '+' or 'Z' (UTC is +00)
|
||||
var tzSign int
|
||||
switch c := str[tzStart]; c {
|
||||
case '-':
|
||||
tzSign = -1
|
||||
case '+':
|
||||
tzSign = +1
|
||||
default:
|
||||
return time.Time{}, fmt.Errorf("expected '-' or '+' at position %v; got %v", tzStart, c)
|
||||
}
|
||||
tzHours := p.mustAtoi(str, tzStart+1, tzStart+3)
|
||||
remainderIdx += 3
|
||||
var tzMin, tzSec int
|
||||
if remainderIdx < len(str) && str[remainderIdx] == ':' {
|
||||
tzMin = p.mustAtoi(str, remainderIdx+1, remainderIdx+3)
|
||||
remainderIdx += 3
|
||||
}
|
||||
if remainderIdx < len(str) && str[remainderIdx] == ':' {
|
||||
tzSec = p.mustAtoi(str, remainderIdx+1, remainderIdx+3)
|
||||
remainderIdx += 3
|
||||
}
|
||||
tzOff = tzSign * ((tzHours * 60 * 60) + (tzMin * 60) + tzSec)
|
||||
} else if tzStart < len(str) && str[tzStart] == 'Z' {
|
||||
// time zone Z separator indicates UTC is +00
|
||||
remainderIdx += 1
|
||||
}
|
||||
|
||||
var isoYear int
|
||||
|
||||
if isBC {
|
||||
isoYear = 1 - year
|
||||
remainderIdx += 3
|
||||
} else {
|
||||
isoYear = year
|
||||
}
|
||||
if remainderIdx < len(str) {
|
||||
return time.Time{}, fmt.Errorf("expected end of input, got %v", str[remainderIdx:])
|
||||
}
|
||||
t := time.Date(isoYear, time.Month(month), day,
|
||||
hour, minute, second, nanoSec,
|
||||
globalLocationCache.getLocation(tzOff))
|
||||
|
||||
if currentLocation != nil {
|
||||
// Set the location of the returned Time based on the session's
|
||||
// TimeZone value, but only if the local time zone database agrees with
|
||||
// the remote database on the offset.
|
||||
lt := t.In(currentLocation)
|
||||
_, newOff := lt.Zone()
|
||||
if newOff == tzOff {
|
||||
t = lt
|
||||
}
|
||||
}
|
||||
|
||||
return t, p.err
|
||||
}
|
||||
|
||||
// Format into Postgres' text format for timestamps.
|
||||
func Format(t time.Time) []byte {
|
||||
// Need to send dates before 0001 A.D. with " BC" suffix, instead of the
|
||||
// minus sign preferred by Go.
|
||||
// Beware, "0000" in ISO is "1 BC", "-0001" is "2 BC" and so on
|
||||
bc := false
|
||||
if t.Year() <= 0 {
|
||||
// flip year sign, and add 1, e.g: "0" will be "1", and "-10" will be "11"
|
||||
t = t.AddDate((-t.Year())*2+1, 0, 0)
|
||||
bc = true
|
||||
}
|
||||
b := []byte(t.Format("2006-01-02 15:04:05.999999999Z07:00"))
|
||||
|
||||
_, offset := t.Zone()
|
||||
offset %= 60
|
||||
if offset != 0 {
|
||||
// RFC3339Nano already printed the minus sign
|
||||
if offset < 0 {
|
||||
offset = -offset
|
||||
}
|
||||
|
||||
b = append(b, ':')
|
||||
if offset < 10 {
|
||||
b = append(b, '0')
|
||||
}
|
||||
b = strconv.AppendInt(b, int64(offset), 10)
|
||||
}
|
||||
|
||||
if bc {
|
||||
b = append(b, " BC"...)
|
||||
}
|
||||
return b
|
||||
}
|
||||
91
vendor/github.com/lib/pq/internal/pqutil/path.go
generated
vendored
Normal file
91
vendor/github.com/lib/pq/internal/pqutil/path.go
generated
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
package pqutil
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// Home gets the PostgreSQL configuration dir in the user's home directory:
|
||||
// %APPDATA%/postgresql on Windows, and $HOME/.postgresql/postgresql.crt
|
||||
// everywhere else.
|
||||
//
|
||||
// Returns an empy string if no home directory was found.
|
||||
//
|
||||
// Matches pqGetHomeDirectory() from PostgreSQL.
|
||||
// https://github.com/postgres/postgres/blob/2b117bb/src/interfaces/libpq/fe-connect.c#L8214
|
||||
func Home(subdir bool) string {
|
||||
if runtime.GOOS == "windows" {
|
||||
// pq uses SHGetFolderPath(), which is deprecated but x/sys/windows has
|
||||
// KnownFolderPath(). We don't really want to pull that in though, so
|
||||
// use APPDATA env. This is also what PostgreSQL uses in some other
|
||||
// codepaths (get_home_path() for example).
|
||||
ad := os.Getenv("APPDATA")
|
||||
if ad == "" {
|
||||
return ""
|
||||
}
|
||||
return filepath.Join(ad, "postgresql")
|
||||
}
|
||||
|
||||
home, _ := os.UserHomeDir()
|
||||
if home == "" {
|
||||
u, err := user.Current()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
home = u.HomeDir
|
||||
}
|
||||
// libpq reads some files from ~/ and some from ~/.postgresql – on Windows
|
||||
// it always uses %APPDATA%/postgresql.
|
||||
if subdir {
|
||||
home = filepath.Join(home, ".postgresql")
|
||||
}
|
||||
return home
|
||||
}
|
||||
|
||||
// ErrNotExists reports if err is a "path doesn't exist" type error.
|
||||
//
|
||||
// fs.ErrNotExist is not enough, as "/dev/null/somefile" will return ENOTDIR
|
||||
// instead of ENOENT.
|
||||
func ErrNotExists(err error) bool {
|
||||
perr := new(os.PathError)
|
||||
if errors.As(err, &perr) && (perr.Err == syscall.ENOENT || perr.Err == syscall.ENOTDIR) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var WarnFD io.Writer = os.Stderr
|
||||
|
||||
// Pgpass gets the filepath to the pgpass file to use, returning "" if a pgpass
|
||||
// file shouldn't be used.
|
||||
func Pgpass(passfile string) string {
|
||||
// Get passfile from the options.
|
||||
if passfile == "" {
|
||||
home := Home(false)
|
||||
if home == "" {
|
||||
return ""
|
||||
}
|
||||
passfile = filepath.Join(home, ".pgpass")
|
||||
}
|
||||
|
||||
// On Win32, the directory is protected, so we don't have to check the file.
|
||||
if runtime.GOOS != "windows" {
|
||||
fi, err := os.Stat(passfile)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
if fi.Mode().Perm()&(0x77) != 0 {
|
||||
fmt.Fprintf(WarnFD,
|
||||
"WARNING: password file %q has group or world access; permissions should be u=rw (0600) or less\n",
|
||||
passfile)
|
||||
return ""
|
||||
}
|
||||
}
|
||||
return passfile
|
||||
}
|
||||
64
vendor/github.com/lib/pq/internal/pqutil/perm.go
generated
vendored
Normal file
64
vendor/github.com/lib/pq/internal/pqutil/perm.go
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
//go:build !windows && !plan9
|
||||
|
||||
package pqutil
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrSSLKeyUnknownOwnership = errors.New("pq: could not get owner information for private key, may not be properly protected")
|
||||
ErrSSLKeyHasWorldPermissions = errors.New("pq: private key has world access; permissions should be u=rw,g=r (0640) if owned by root, or u=rw (0600), or less")
|
||||
)
|
||||
|
||||
// SSLKeyPermissions checks the permissions on user-supplied SSL key files,
|
||||
// which should have very little access. libpq does not check key file
|
||||
// permissions on Windows.
|
||||
//
|
||||
// If the file is owned by the same user the process is running as, the file
|
||||
// should only have 0600. If the file is owned by root, and the group matches
|
||||
// the group that the process is running in, the permissions cannot be more than
|
||||
// 0640. The file should never have world permissions.
|
||||
//
|
||||
// Returns an error when the permission check fails.
|
||||
func SSLKeyPermissions(sslkey string) error {
|
||||
fi, err := os.Stat(sslkey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return CheckPermissions(fi)
|
||||
}
|
||||
|
||||
func CheckPermissions(fi os.FileInfo) error {
|
||||
// The maximum permissions that a private key file owned by a regular user
|
||||
// is allowed to have. This translates to u=rw. Regardless of if we're
|
||||
// running as root or not, 0600 is acceptable, so we return if no bits
|
||||
// beyond the regular user permission mask are set.
|
||||
if fi.Mode().Perm()&^os.FileMode(0o600) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// We need to pull the Unix file information to get the file's owner.
|
||||
// If we can't access it, there's some sort of operating system level error
|
||||
// and we should fail rather than attempting to use faulty information.
|
||||
sys, ok := fi.Sys().(*syscall.Stat_t)
|
||||
if !ok {
|
||||
return ErrSSLKeyUnknownOwnership
|
||||
}
|
||||
|
||||
// if the file is owned by root, we allow 0640 (u=rw,g=r) to match what
|
||||
// Postgres does.
|
||||
if sys.Uid == 0 {
|
||||
// The maximum permissions that a private key file owned by root is
|
||||
// allowed to have. This translates to u=rw,g=r.
|
||||
if fi.Mode().Perm()&^os.FileMode(0o640) != 0 {
|
||||
return ErrSSLKeyHasWorldPermissions
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
return ErrSSLKeyHasWorldPermissions
|
||||
}
|
||||
12
vendor/github.com/lib/pq/internal/pqutil/perm_unsupported.go
generated
vendored
Normal file
12
vendor/github.com/lib/pq/internal/pqutil/perm_unsupported.go
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
//go:build windows || plan9
|
||||
|
||||
package pqutil
|
||||
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
ErrSSLKeyUnknownOwnership = errors.New("unused")
|
||||
ErrSSLKeyHasWorldPermissions = errors.New("unused")
|
||||
)
|
||||
|
||||
func SSLKeyPermissions(sslkey string) error { return nil }
|
||||
32
vendor/github.com/lib/pq/internal/pqutil/pqutil.go
generated
vendored
Normal file
32
vendor/github.com/lib/pq/internal/pqutil/pqutil.go
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
package pqutil
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ParseBool is like strconv.ParseBool, but also accepts "yes"/"no" and
|
||||
// "on"/"off".
|
||||
func ParseBool(str string) (bool, error) {
|
||||
switch str {
|
||||
case "1", "t", "T", "true", "TRUE", "True", "yes", "on":
|
||||
return true, nil
|
||||
case "0", "f", "F", "false", "FALSE", "False", "no", "off":
|
||||
return false, nil
|
||||
}
|
||||
return false, &strconv.NumError{Func: "ParseBool", Num: str, Err: strconv.ErrSyntax}
|
||||
}
|
||||
|
||||
func Join[S ~[]E, E ~string](s S) string {
|
||||
var b strings.Builder
|
||||
for i := range s {
|
||||
if i > 0 {
|
||||
b.WriteString(", ")
|
||||
}
|
||||
if i == len(s)-1 {
|
||||
b.WriteString("or ")
|
||||
}
|
||||
b.WriteString(string(s[i]))
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
9
vendor/github.com/lib/pq/internal/pqutil/user_other.go
generated
vendored
Normal file
9
vendor/github.com/lib/pq/internal/pqutil/user_other.go
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
//go:build js || android || hurd || zos || wasip1 || appengine
|
||||
|
||||
package pqutil
|
||||
|
||||
import "errors"
|
||||
|
||||
func User() (string, error) {
|
||||
return "", errors.New("pqutil.User: not supported on current platform")
|
||||
}
|
||||
25
vendor/github.com/lib/pq/internal/pqutil/user_posix.go
generated
vendored
Normal file
25
vendor/github.com/lib/pq/internal/pqutil/user_posix.go
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
//go:build !windows && !js && !android && !hurd && !zos && !wasip1 && !appengine
|
||||
|
||||
package pqutil
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/user"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func User() (string, error) {
|
||||
env := "USER"
|
||||
if runtime.GOOS == "plan9" {
|
||||
env = "user"
|
||||
}
|
||||
if n := os.Getenv(env); n != "" {
|
||||
return n, nil
|
||||
}
|
||||
|
||||
u, err := user.Current()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return u.Username, nil
|
||||
}
|
||||
28
vendor/github.com/lib/pq/internal/pqutil/user_windows.go
generated
vendored
Normal file
28
vendor/github.com/lib/pq/internal/pqutil/user_windows.go
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
//go:build windows && !appengine
|
||||
|
||||
package pqutil
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func User() (string, error) {
|
||||
// Perform Windows user name lookup identically to libpq.
|
||||
//
|
||||
// The PostgreSQL code makes use of the legacy Win32 function GetUserName,
|
||||
// and that function has not been imported into stock Go. GetUserNameEx is
|
||||
// available though, the difference being that a wider range of names are
|
||||
// available. To get the output to be the same as GetUserName, only the
|
||||
// base (or last) component of the result is returned.
|
||||
var (
|
||||
name = make([]uint16, 128)
|
||||
pwnameSz = uint32(len(name)) - 1
|
||||
)
|
||||
err := syscall.GetUserNameEx(syscall.NameSamCompatible, &name[0], &pwnameSz)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
s := syscall.UTF16ToString(name)
|
||||
return filepath.Base(s), nil
|
||||
}
|
||||
186
vendor/github.com/lib/pq/internal/proto/proto.go
generated
vendored
Normal file
186
vendor/github.com/lib/pq/internal/proto/proto.go
generated
vendored
Normal file
@@ -0,0 +1,186 @@
|
||||
// From src/include/libpq/protocol.h and src/include/libpq/pqcomm.h – PostgreSQL 18.1
|
||||
|
||||
package proto
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Constants from pqcomm.h
|
||||
const (
|
||||
ProtocolVersion30 = (3 << 16) | 0 //lint:ignore SA4016 x
|
||||
ProtocolVersion32 = (3 << 16) | 2 // PostgreSQL ≥18.
|
||||
CancelRequestCode = (1234 << 16) | 5678
|
||||
NegotiateSSLCode = (1234 << 16) | 5679
|
||||
NegotiateGSSCode = (1234 << 16) | 5680
|
||||
)
|
||||
|
||||
// Constants from fe-connect.c
|
||||
const (
|
||||
MaxErrlen = 30_000 // https://github.com/postgres/postgres/blob/c6a10a89f/src/interfaces/libpq/fe-connect.c#L4067
|
||||
)
|
||||
|
||||
// RequestCode is a request codes sent by the frontend.
|
||||
type RequestCode byte
|
||||
|
||||
// These are the request codes sent by the frontend.
|
||||
const (
|
||||
Bind = RequestCode('B')
|
||||
Close = RequestCode('C')
|
||||
Describe = RequestCode('D')
|
||||
Execute = RequestCode('E')
|
||||
FunctionCall = RequestCode('F')
|
||||
Flush = RequestCode('H')
|
||||
Parse = RequestCode('P')
|
||||
Query = RequestCode('Q')
|
||||
Sync = RequestCode('S')
|
||||
Terminate = RequestCode('X')
|
||||
CopyFail = RequestCode('f')
|
||||
GSSResponse = RequestCode('p')
|
||||
PasswordMessage = RequestCode('p')
|
||||
SASLInitialResponse = RequestCode('p')
|
||||
SASLResponse = RequestCode('p')
|
||||
CopyDoneRequest = RequestCode('c')
|
||||
CopyDataRequest = RequestCode('d')
|
||||
)
|
||||
|
||||
func (r RequestCode) String() string {
|
||||
s, ok := map[RequestCode]string{
|
||||
Bind: "Bind",
|
||||
Close: "Close",
|
||||
Describe: "Describe",
|
||||
Execute: "Execute",
|
||||
FunctionCall: "FunctionCall",
|
||||
Flush: "Flush",
|
||||
Parse: "Parse",
|
||||
Query: "Query",
|
||||
Sync: "Sync",
|
||||
Terminate: "Terminate",
|
||||
CopyFail: "CopyFail",
|
||||
// These are all the same :-/
|
||||
//GSSResponse: "GSSResponse",
|
||||
PasswordMessage: "PasswordMessage",
|
||||
//SASLInitialResponse: "SASLInitialResponse",
|
||||
//SASLResponse: "SASLResponse",
|
||||
CopyDoneRequest: "CopyDone",
|
||||
CopyDataRequest: "CopyData",
|
||||
}[r]
|
||||
if !ok {
|
||||
s = "<unknown>"
|
||||
}
|
||||
c := string(r)
|
||||
if r <= 0x1f || r == 0x7f {
|
||||
c = fmt.Sprintf("0x%x", string(r))
|
||||
}
|
||||
return "(" + c + ") " + s
|
||||
}
|
||||
|
||||
// ResponseCode is a response codes sent by the backend.
|
||||
type ResponseCode byte
|
||||
|
||||
// These are the response codes sent by the backend.
|
||||
const (
|
||||
ParseComplete = ResponseCode('1')
|
||||
BindComplete = ResponseCode('2')
|
||||
CloseComplete = ResponseCode('3')
|
||||
NotificationResponse = ResponseCode('A')
|
||||
CommandComplete = ResponseCode('C')
|
||||
DataRow = ResponseCode('D')
|
||||
ErrorResponse = ResponseCode('E')
|
||||
CopyInResponse = ResponseCode('G')
|
||||
CopyOutResponse = ResponseCode('H')
|
||||
EmptyQueryResponse = ResponseCode('I')
|
||||
BackendKeyData = ResponseCode('K')
|
||||
NoticeResponse = ResponseCode('N')
|
||||
AuthenticationRequest = ResponseCode('R')
|
||||
ParameterStatus = ResponseCode('S')
|
||||
RowDescription = ResponseCode('T')
|
||||
FunctionCallResponse = ResponseCode('V')
|
||||
CopyBothResponse = ResponseCode('W')
|
||||
ReadyForQuery = ResponseCode('Z')
|
||||
NoData = ResponseCode('n')
|
||||
PortalSuspended = ResponseCode('s')
|
||||
ParameterDescription = ResponseCode('t')
|
||||
NegotiateProtocolVersion = ResponseCode('v')
|
||||
CopyDoneResponse = ResponseCode('c')
|
||||
CopyDataResponse = ResponseCode('d')
|
||||
)
|
||||
|
||||
func (r ResponseCode) String() string {
|
||||
s, ok := map[ResponseCode]string{
|
||||
ParseComplete: "ParseComplete",
|
||||
BindComplete: "BindComplete",
|
||||
CloseComplete: "CloseComplete",
|
||||
NotificationResponse: "NotificationResponse",
|
||||
CommandComplete: "CommandComplete",
|
||||
DataRow: "DataRow",
|
||||
ErrorResponse: "ErrorResponse",
|
||||
CopyInResponse: "CopyInResponse",
|
||||
CopyOutResponse: "CopyOutResponse",
|
||||
EmptyQueryResponse: "EmptyQueryResponse",
|
||||
BackendKeyData: "BackendKeyData",
|
||||
NoticeResponse: "NoticeResponse",
|
||||
AuthenticationRequest: "AuthRequest",
|
||||
ParameterStatus: "ParamStatus",
|
||||
RowDescription: "RowDescription",
|
||||
FunctionCallResponse: "FunctionCallResponse",
|
||||
CopyBothResponse: "CopyBothResponse",
|
||||
ReadyForQuery: "ReadyForQuery",
|
||||
NoData: "NoData",
|
||||
PortalSuspended: "PortalSuspended",
|
||||
ParameterDescription: "ParamDescription",
|
||||
NegotiateProtocolVersion: "NegotiateProtocolVersion",
|
||||
CopyDoneResponse: "CopyDone",
|
||||
CopyDataResponse: "CopyData",
|
||||
}[r]
|
||||
if !ok {
|
||||
s = "<unknown>"
|
||||
}
|
||||
c := string(r)
|
||||
if r <= 0x1f || r == 0x7f {
|
||||
c = fmt.Sprintf("0x%x", string(r))
|
||||
}
|
||||
return "(" + c + ") " + s
|
||||
}
|
||||
|
||||
// AuthCode are authentication request codes sent by the backend.
|
||||
type AuthCode int32
|
||||
|
||||
// These are the authentication request codes sent by the backend.
|
||||
const (
|
||||
AuthReqOk = AuthCode(0) // User is authenticated
|
||||
AuthReqKrb4 = AuthCode(1) // Kerberos V4. Not supported any more.
|
||||
AuthReqKrb5 = AuthCode(2) // Kerberos V5. Not supported any more.
|
||||
AuthReqPassword = AuthCode(3) // Password
|
||||
AuthReqCrypt = AuthCode(4) // crypt password. Not supported any more.
|
||||
AuthReqMD5 = AuthCode(5) // md5 password
|
||||
_ = AuthCode(6) // 6 is available. It was used for SCM creds, not supported any more.
|
||||
AuthReqGSS = AuthCode(7) // GSSAPI without wrap()
|
||||
AuthReqGSSCont = AuthCode(8) // Continue GSS exchanges
|
||||
AuthReqSSPI = AuthCode(9) // SSPI negotiate without wrap()
|
||||
AuthReqSASL = AuthCode(10) // Begin SASL authentication
|
||||
AuthReqSASLCont = AuthCode(11) // Continue SASL authentication
|
||||
AuthReqSASLFin = AuthCode(12) // Final SASL message
|
||||
)
|
||||
|
||||
func (a AuthCode) String() string {
|
||||
s, ok := map[AuthCode]string{
|
||||
AuthReqOk: "ok",
|
||||
AuthReqKrb4: "krb4",
|
||||
AuthReqKrb5: "krb5",
|
||||
AuthReqPassword: "password",
|
||||
AuthReqCrypt: "crypt",
|
||||
AuthReqMD5: "md5",
|
||||
AuthReqGSS: "GDD",
|
||||
AuthReqGSSCont: "GSSCont",
|
||||
AuthReqSSPI: "SSPI",
|
||||
AuthReqSASL: "SASL",
|
||||
AuthReqSASLCont: "SASLCont",
|
||||
AuthReqSASLFin: "SASLFin",
|
||||
}[a]
|
||||
if !ok {
|
||||
s = "<unknown>"
|
||||
}
|
||||
return s + " (" + strconv.Itoa(int(a)) + ")"
|
||||
}
|
||||
7
vendor/github.com/lib/pq/internal/proto/sz_32.go
generated
vendored
Normal file
7
vendor/github.com/lib/pq/internal/proto/sz_32.go
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
//go:build 386 || arm || mips || mipsle
|
||||
|
||||
package proto
|
||||
|
||||
import "math"
|
||||
|
||||
const MaxUint32 = math.MaxInt
|
||||
7
vendor/github.com/lib/pq/internal/proto/sz_64.go
generated
vendored
Normal file
7
vendor/github.com/lib/pq/internal/proto/sz_64.go
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
//go:build !386 && !arm && !mips && !mipsle
|
||||
|
||||
package proto
|
||||
|
||||
import "math"
|
||||
|
||||
const MaxUint32 = math.MaxUint32
|
||||
Reference in New Issue
Block a user