aboutsummaryrefslogtreecommitdiffstats
path: root/core/vm/sqlvm/errors/errors.go
blob: e69993300c8ef1de30f3b3676d6e9c96548f3468 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
package errors

import (
    "fmt"
    "strconv"
    "strings"
)

// Error collects error information which should be reported to users.
type Error struct {
    // These keys are parts of SQL VM ABI. Database contract callers can
    // obtain values stored in these fields from function return values.
    Position uint32 // Position is the offset in bytes to the error location.
    Length   uint32 // Length is the length in bytes of the error token.
    Category ErrorCategory
    Code     ErrorCode

    // These keys are only used for debugging purposes and not included in ABI.
    // Values stored in these fields are not guaranteed to be stable, so they
    // MUST NOT be returned to the contract caller.
    Prefix  string // Prefix identified the cause of the error.
    Message string // Message provides detailed the error message.
}

func (e Error) Error() string {
    b := strings.Builder{}
    // It is possible for an error to have zero length because not all errors
    // correspond to tokens. The parser can report an error with no length when
    // it encounters an unexpected token.
    if e.Position > 0 || e.Length > 0 {
        b.WriteString(fmt.Sprintf("offset %d", e.Position))
        if e.Length > 0 {
            b.WriteString(fmt.Sprintf(", length %d", e.Length))
        }
    } else {
        b.WriteString("unknown location")
    }
    b.WriteString(fmt.Sprintf(", category %d (%s), code %d (%s)",
        e.Category, e.Category, e.Code, e.Code))
    if e.Prefix != "" {
        b.WriteString(", hint ")
        b.WriteString(strconv.Quote(e.Prefix))
    }
    if e.Message != "" {
        b.WriteString(", message: ")
        b.WriteString(e.Message)
    }
    return b.String()
}

// ErrorList is a list of Error.
type ErrorList []Error

func (e ErrorList) Error() string {
    b := strings.Builder{}
    for i := range e {
        if i > 0 {
            b.WriteByte('\n')
        }
        b.WriteString(e[i].Error())
    }
    return b.String()
}

// ErrorCategory is used to distinguish errors come from different phases.
type ErrorCategory uint16

// Error category starts from 1. Zero value is invalid.
const (
    ErrorCategoryNil ErrorCategory = iota
    ErrorCategoryLimit
    ErrorCategoryGrammar
    ErrorCategorySemantic
    ErrorCategoryRuntime
)

var errorCategoryMap = [...]string{
    ErrorCategoryLimit:    "limit",
    ErrorCategoryGrammar:  "grammar",
    ErrorCategorySemantic: "semantic",
    ErrorCategoryRuntime:  "runtime",
}

func (c ErrorCategory) Error() string {
    return errorCategoryMap[c]
}

// ErrorCode describes the reason of the error.
type ErrorCode uint16

// Error code starts from 1. Zero value is invalid.
const (
    ErrorCodeNil ErrorCode = iota
    ErrorCodeDepthLimitReached
    ErrorCodeParser
    ErrorCodeInvalidIntegerSyntax
    ErrorCodeInvalidNumberSyntax
    ErrorCodeIntegerOutOfRange
    ErrorCodeNumberOutOfRange
    ErrorCodeFractionalPartTooLong
    ErrorCodeEscapeSequenceTooShort
    ErrorCodeInvalidUnicodeCodePoint
    ErrorCodeUnknownEscapeSequence
    ErrorCodeInvalidBytesSize
    ErrorCodeInvalidIntSize
    ErrorCodeInvalidUintSize
    ErrorCodeInvalidFixedSize
    ErrorCodeInvalidUfixedSize
    ErrorCodeInvalidFixedFractionalDigits
    ErrorCodeInvalidUfixedFractionalDigits
    ErrorCodeDecimalEncode
    ErrorCodeDecimalDecode

    // Runtime Error
    ErrorCodeInvalidOperandNum
    ErrorCodeInvalidDataType
    ErrorCodeOverflow
    ErrorCodeUnderflow
    ErrorCodeIndexOutOfRange
    ErrorCodeInvalidCastType
    ErrorCodeDividedByZero
    ErrorCodeNegDecimalToUint64
    ErrorCodeDataLengthNotMatch
    ErrorCodeMultipleEscapeByte
    ErrorCodePendingEscapeByte
    ErrorCodeNoSuchFunction
)

var errorCodeMap = [...]string{
    ErrorCodeDepthLimitReached:             "depth limit reached",
    ErrorCodeParser:                        "parser error",
    ErrorCodeInvalidIntegerSyntax:          "invalid integer syntax",
    ErrorCodeInvalidNumberSyntax:           "invalid number syntax",
    ErrorCodeIntegerOutOfRange:             "integer out of range",
    ErrorCodeNumberOutOfRange:              "number out of range",
    ErrorCodeFractionalPartTooLong:         "fractional part too long",
    ErrorCodeEscapeSequenceTooShort:        "escape sequence too short",
    ErrorCodeInvalidUnicodeCodePoint:       "invalid unicode code point",
    ErrorCodeUnknownEscapeSequence:         "unknown escape sequence",
    ErrorCodeInvalidBytesSize:              "invalid bytes size",
    ErrorCodeInvalidIntSize:                "invalid int size",
    ErrorCodeInvalidUintSize:               "invalid uint size",
    ErrorCodeInvalidFixedSize:              "invalid fixed size",
    ErrorCodeInvalidUfixedSize:             "invalid ufixed size",
    ErrorCodeInvalidFixedFractionalDigits:  "invalid fixed fractional digits",
    ErrorCodeInvalidUfixedFractionalDigits: "invalid ufixed fractional digits",
    ErrorCodeDecimalEncode:                 "decimal encode failed",
    ErrorCodeDecimalDecode:                 "decimal decode failed",
    // Runtime Error
    ErrorCodeInvalidOperandNum:  "invalid operand number",
    ErrorCodeInvalidDataType:    "invalid data type",
    ErrorCodeOverflow:           "overflow",
    ErrorCodeUnderflow:          "underflow",
    ErrorCodeIndexOutOfRange:    "index out of range",
    ErrorCodeInvalidCastType:    "invalid cast type",
    ErrorCodeDividedByZero:      "divide by zero",
    ErrorCodeNegDecimalToUint64: "negative deciaml to uint64",
    ErrorCodeDataLengthNotMatch: "data length not match",
    ErrorCodeMultipleEscapeByte: "multiple escape byte",
    ErrorCodePendingEscapeByte:  "pending escape byte",
    ErrorCodeNoSuchFunction:     "no such function",
}

func (c ErrorCode) Error() string {
    return errorCodeMap[c]
}