CatchVectorizedRuntimeError executes operation, catches a runtime error if it is coming from the vectorized engine, and returns it. If an error not related to the vectorized engine occurs, it is not recovered from.
(operation func())
| 43 | // it is coming from the vectorized engine, and returns it. If an error not |
| 44 | // related to the vectorized engine occurs, it is not recovered from. |
| 45 | func CatchVectorizedRuntimeError(operation func()) (retErr error) { |
| 46 | defer func() { |
| 47 | panicObj := recover() |
| 48 | if panicObj == nil { |
| 49 | // No panic happened, so the operation must have been executed |
| 50 | // successfully. |
| 51 | return |
| 52 | } |
| 53 | |
| 54 | // First check for error types that should only come from the vectorized |
| 55 | // engine. |
| 56 | if err, ok := panicObj.(error); ok { |
| 57 | // StorageError was caused by something below SQL, and represents an error |
| 58 | // that we'd simply like to propagate along. |
| 59 | var se *StorageError |
| 60 | // notInternalError is an error from the vectorized engine that we'd |
| 61 | // simply like to propagate along. |
| 62 | var nie *notInternalError |
| 63 | // internalError is an error from the vectorized engine that might need to |
| 64 | // be returned to the client with a stacktrace, sentry report, and |
| 65 | // "internal error" designation. |
| 66 | var ie *internalError |
| 67 | passthrough := errors.As(err, &se) || errors.As(err, &nie) |
| 68 | if errors.As(err, &ie) { |
| 69 | // Unwrap so that internalError doesn't show up in sentry reports. |
| 70 | retErr = ie.Unwrap() |
| 71 | // If the internal error doesn't already have an error code, mark it as |
| 72 | // an assertion error so that we generate a sentry report. (We don't do |
| 73 | // this for StorageError, notInternalError, or context.Canceled to avoid |
| 74 | // creating unnecessary sentry reports.) |
| 75 | if !passthrough && !errors.Is(retErr, context.Canceled) { |
| 76 | if code := pgerror.GetPGCode(retErr); code == pgcode.Uncategorized { |
| 77 | retErr = errors.NewAssertionErrorWithWrappedErrf( |
| 78 | retErr, "unexpected error from the vectorized engine", |
| 79 | ) |
| 80 | } |
| 81 | } |
| 82 | return |
| 83 | } |
| 84 | if passthrough { |
| 85 | retErr = err |
| 86 | return |
| 87 | } |
| 88 | } |
| 89 | |
| 90 | // For other types of errors, we need to check whence the panic originated |
| 91 | // to know what to do. If the panic originated in the vectorized engine, we |
| 92 | // can safely return it as a normal error knowing that any illegal state |
| 93 | // will be cleaned up when the statement finishes. If the panic originated |
| 94 | // lower in the stack, however, we must treat it as unrecoverable because it |
| 95 | // could indicate an illegal state that might persist even after this |
| 96 | // statement finishes. |
| 97 | // |
| 98 | // To check whence the panic originated, we find the frame just before the |
| 99 | // panic frame. |
| 100 | var panicLineFound bool |
| 101 | var panicEmittedFrom string |
| 102 | // Usually, we'll find the offending frame within 3 program counters, |