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:
324
vendor/github.com/lib/pq/error.go
generated
vendored
Normal file
324
vendor/github.com/lib/pq/error.go
generated
vendored
Normal file
@@ -0,0 +1,324 @@
|
||||
package pq
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/lib/pq/pqerror"
|
||||
)
|
||||
|
||||
// Error returned by the PostgreSQL server.
|
||||
//
|
||||
// The [Error] method returns the error message and error code:
|
||||
//
|
||||
// pq: invalid input syntax for type json (22P02)
|
||||
//
|
||||
// The [ErrorWithDetail] method also includes the error Detail, Hint, and
|
||||
// location context (if any):
|
||||
//
|
||||
// ERROR: invalid input syntax for type json (22P02)
|
||||
// DETAIL: Token "asd" is invalid.
|
||||
// CONTEXT: line 5, column 8:
|
||||
//
|
||||
// 3 | 'def',
|
||||
// 4 | 123,
|
||||
// 5 | 'foo', 'asd'::jsonb
|
||||
// ^
|
||||
type Error struct {
|
||||
// [Efatal], [Epanic], [Ewarning], [Enotice], [Edebug], [Einfo], or [Elog].
|
||||
// Always present.
|
||||
Severity string
|
||||
|
||||
// SQLSTATE code. Always present.
|
||||
Code pqerror.Code
|
||||
|
||||
// Primary human-readable error message. This should be accurate but terse
|
||||
// (typically one line). Always present.
|
||||
Message string
|
||||
|
||||
// Optional secondary error message carrying more detail about the problem.
|
||||
// Might run to multiple lines.
|
||||
Detail string
|
||||
|
||||
// Optional suggestion what to do about the problem. This is intended to
|
||||
// differ from Detail in that it offers advice (potentially inappropriate)
|
||||
// rather than hard facts. Might run to multiple lines.
|
||||
Hint string
|
||||
|
||||
// error position as an index into the original query string, as decimal
|
||||
// ASCII integer. The first character has index 1, and positions are
|
||||
// measured in characters not bytes.
|
||||
Position string
|
||||
|
||||
// This is defined the same as the Position field, but it is used when the
|
||||
// cursor position refers to an internally generated command rather than the
|
||||
// one submitted by the client. The InternalQuery field will always appear
|
||||
// when this field appears.
|
||||
InternalPosition string
|
||||
|
||||
// Text of a failed internally-generated command. This could be, for
|
||||
// example, an SQL query issued by a PL/pgSQL function.
|
||||
InternalQuery string
|
||||
|
||||
// An indication of the context in which the error occurred. Presently this
|
||||
// includes a call stack traceback of active procedural language functions
|
||||
// and internally-generated queries. The trace is one entry per line, most
|
||||
// recent first.
|
||||
Where string
|
||||
|
||||
// If the error was associated with a specific database object, the name of
|
||||
// the schema containing that object, if any.
|
||||
Schema string
|
||||
|
||||
// If the error was associated with a specific table, the name of the table.
|
||||
// (Refer to the schema name field for the name of the table's schema.)
|
||||
Table string
|
||||
|
||||
// If the error was associated with a specific table column, the name of the
|
||||
// column. (Refer to the schema and table name fields to identify the
|
||||
// table.)
|
||||
Column string
|
||||
|
||||
// If the error was associated with a specific data type, the name of the
|
||||
// data type. (Refer to the schema name field for the name of the data
|
||||
// type's schema.)
|
||||
DataTypeName string
|
||||
|
||||
// If the error was associated with a specific constraint, the name of the
|
||||
// constraint. Refer to fields listed above for the associated table or
|
||||
// domain. (For this purpose, indexes are treated as constraints, even if
|
||||
// they weren't created with constraint syntax.)
|
||||
Constraint string
|
||||
|
||||
// File name of the source-code location where the error was reported.
|
||||
File string
|
||||
|
||||
// Line number of the source-code location where the error was reported.
|
||||
Line string
|
||||
|
||||
// Name of the source-code routine reporting the error.
|
||||
Routine string
|
||||
|
||||
query string
|
||||
}
|
||||
|
||||
type (
|
||||
// ErrorCode is a five-character error code.
|
||||
//
|
||||
// Deprecated: use pqerror.Code
|
||||
//
|
||||
//go:fix inline
|
||||
ErrorCode = pqerror.Code
|
||||
|
||||
// ErrorClass is only the class part of an error code.
|
||||
//
|
||||
// Deprecated: use pqerror.Class
|
||||
//
|
||||
//go:fix inline
|
||||
ErrorClass = pqerror.Class
|
||||
)
|
||||
|
||||
func parseError(r *readBuf, q string) *Error {
|
||||
err := &Error{query: q}
|
||||
for t := r.byte(); t != 0; t = r.byte() {
|
||||
msg := r.string()
|
||||
switch t {
|
||||
case 'S':
|
||||
err.Severity = msg
|
||||
case 'C':
|
||||
err.Code = pqerror.Code(msg)
|
||||
case 'M':
|
||||
err.Message = msg
|
||||
case 'D':
|
||||
err.Detail = msg
|
||||
case 'H':
|
||||
err.Hint = msg
|
||||
case 'P':
|
||||
err.Position = msg
|
||||
case 'p':
|
||||
err.InternalPosition = msg
|
||||
case 'q':
|
||||
err.InternalQuery = msg
|
||||
case 'W':
|
||||
err.Where = msg
|
||||
case 's':
|
||||
err.Schema = msg
|
||||
case 't':
|
||||
err.Table = msg
|
||||
case 'c':
|
||||
err.Column = msg
|
||||
case 'd':
|
||||
err.DataTypeName = msg
|
||||
case 'n':
|
||||
err.Constraint = msg
|
||||
case 'F':
|
||||
err.File = msg
|
||||
case 'L':
|
||||
err.Line = msg
|
||||
case 'R':
|
||||
err.Routine = msg
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Fatal returns true if the Error Severity is fatal.
|
||||
func (e *Error) Fatal() bool { return e.Severity == pqerror.SeverityFatal }
|
||||
|
||||
// SQLState returns the SQLState of the error.
|
||||
func (e *Error) SQLState() string { return string(e.Code) }
|
||||
|
||||
func (e *Error) Error() string {
|
||||
msg := e.Message
|
||||
if e.query != "" && e.Position != "" {
|
||||
pos, err := strconv.Atoi(e.Position)
|
||||
if err == nil {
|
||||
lines := strings.Split(e.query, "\n")
|
||||
line, col := posToLine(pos, lines)
|
||||
if len(lines) == 1 {
|
||||
msg += " at column " + strconv.Itoa(col)
|
||||
} else {
|
||||
msg += " at position " + strconv.Itoa(line) + ":" + strconv.Itoa(col)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if e.Code != "" {
|
||||
return "pq: " + msg + " (" + string(e.Code) + ")"
|
||||
}
|
||||
return "pq: " + msg
|
||||
}
|
||||
|
||||
// ErrorWithDetail returns the error message with detailed information and
|
||||
// location context (if any).
|
||||
//
|
||||
// See the documentation on [Error].
|
||||
func (e *Error) ErrorWithDetail() string {
|
||||
b := new(strings.Builder)
|
||||
b.Grow(len(e.Message) + len(e.Detail) + len(e.Hint) + 30)
|
||||
b.WriteString("ERROR: ")
|
||||
b.WriteString(e.Message)
|
||||
if e.Code != "" {
|
||||
b.WriteString(" (")
|
||||
b.WriteString(string(e.Code))
|
||||
b.WriteByte(')')
|
||||
}
|
||||
if e.Detail != "" {
|
||||
b.WriteString("\nDETAIL: ")
|
||||
b.WriteString(e.Detail)
|
||||
}
|
||||
if e.Hint != "" {
|
||||
b.WriteString("\nHINT: ")
|
||||
b.WriteString(e.Hint)
|
||||
}
|
||||
|
||||
if e.query != "" && e.Position != "" {
|
||||
b.Grow(512)
|
||||
pos, err := strconv.Atoi(e.Position)
|
||||
if err != nil {
|
||||
return b.String()
|
||||
}
|
||||
lines := strings.Split(e.query, "\n")
|
||||
line, col := posToLine(pos, lines)
|
||||
|
||||
fmt.Fprintf(b, "\nCONTEXT: line %d, column %d:\n\n", line, col)
|
||||
if line > 2 {
|
||||
fmt.Fprintf(b, "% 7d | %s\n", line-2, expandTab(lines[line-3]))
|
||||
}
|
||||
if line > 1 {
|
||||
fmt.Fprintf(b, "% 7d | %s\n", line-1, expandTab(lines[line-2]))
|
||||
}
|
||||
/// Expand tabs, so that the ^ is at at the correct position, but leave
|
||||
/// "column 10-13" intact. Adjusting this to the visual column would be
|
||||
/// better, but we don't know the tabsize of the user in their editor,
|
||||
/// which can be 8, 4, 2, or something else. We can't know. So leaving
|
||||
/// it as the character index is probably the "most correct".
|
||||
expanded := expandTab(lines[line-1])
|
||||
diff := len(expanded) - len(lines[line-1])
|
||||
fmt.Fprintf(b, "% 7d | %s\n", line, expanded)
|
||||
fmt.Fprintf(b, "% 10s%s%s\n", "", strings.Repeat(" ", col-1+diff), "^")
|
||||
}
|
||||
|
||||
return b.String()
|
||||
}
|
||||
|
||||
func posToLine(pos int, lines []string) (line, col int) {
|
||||
read := 0
|
||||
for i := range lines {
|
||||
line++
|
||||
ll := utf8.RuneCountInString(lines[i]) + 1 // +1 for the removed newline
|
||||
if read+ll >= pos {
|
||||
col = max(pos-read, 1) // Should be lower than 1, but just in case.
|
||||
break
|
||||
}
|
||||
read += ll
|
||||
}
|
||||
return line, col
|
||||
}
|
||||
|
||||
func expandTab(s string) string {
|
||||
var (
|
||||
b strings.Builder
|
||||
l int
|
||||
fill = func(n int) string {
|
||||
b := make([]byte, n)
|
||||
for i := range b {
|
||||
b[i] = ' '
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
)
|
||||
b.Grow(len(s))
|
||||
for _, r := range s {
|
||||
switch r {
|
||||
case '\t':
|
||||
tw := 8 - l%8
|
||||
b.WriteString(fill(tw))
|
||||
l += tw
|
||||
default:
|
||||
b.WriteRune(r)
|
||||
l += 1
|
||||
}
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
|
||||
func (cn *conn) handleError(reported error, query ...string) error {
|
||||
switch err := reported.(type) {
|
||||
case nil:
|
||||
return nil
|
||||
case runtime.Error, *net.OpError:
|
||||
cn.err.set(driver.ErrBadConn)
|
||||
case *safeRetryError:
|
||||
cn.err.set(driver.ErrBadConn)
|
||||
reported = driver.ErrBadConn
|
||||
case *Error:
|
||||
if len(query) > 0 && query[0] != "" {
|
||||
err.query = query[0]
|
||||
reported = err
|
||||
}
|
||||
if err.Fatal() {
|
||||
reported = driver.ErrBadConn
|
||||
}
|
||||
case error:
|
||||
if err == io.EOF || err == io.ErrUnexpectedEOF || err.Error() == "remote error: handshake failure" {
|
||||
reported = driver.ErrBadConn
|
||||
}
|
||||
default:
|
||||
cn.err.set(driver.ErrBadConn)
|
||||
reported = fmt.Errorf("pq: unknown error %T: %[1]s", err)
|
||||
}
|
||||
|
||||
// Any time we return ErrBadConn, we need to remember it since *Tx doesn't
|
||||
// mark the connection bad in database/sql.
|
||||
if reported == driver.ErrBadConn {
|
||||
cn.err.set(driver.ErrBadConn)
|
||||
}
|
||||
return reported
|
||||
}
|
||||
Reference in New Issue
Block a user