github.com/snowflakedb/gosnowflake@v1.9.0/errors.go (about)

     1  // Copyright (c) 2017-2022 Snowflake Computing Inc. All rights reserved.
     2  
     3  package gosnowflake
     4  
     5  import (
     6  	"fmt"
     7  	"runtime/debug"
     8  	"strconv"
     9  	"time"
    10  )
    11  
    12  // SnowflakeError is a error type including various Snowflake specific information.
    13  type SnowflakeError struct {
    14  	Number         int
    15  	SQLState       string
    16  	QueryID        string
    17  	Message        string
    18  	MessageArgs    []interface{}
    19  	IncludeQueryID bool // TODO: populate this in connection
    20  }
    21  
    22  func (se *SnowflakeError) Error() string {
    23  	message := se.Message
    24  	if len(se.MessageArgs) > 0 {
    25  		message = fmt.Sprintf(se.Message, se.MessageArgs...)
    26  	}
    27  	if se.SQLState != "" {
    28  		if se.IncludeQueryID {
    29  			return fmt.Sprintf("%06d (%s): %s: %s", se.Number, se.SQLState, se.QueryID, message)
    30  		}
    31  		return fmt.Sprintf("%06d (%s): %s", se.Number, se.SQLState, message)
    32  	}
    33  	if se.IncludeQueryID {
    34  		return fmt.Sprintf("%06d: %s: %s", se.Number, se.QueryID, message)
    35  	}
    36  	return fmt.Sprintf("%06d: %s", se.Number, message)
    37  }
    38  
    39  func (se *SnowflakeError) generateTelemetryExceptionData() *telemetryData {
    40  	data := &telemetryData{
    41  		Message: map[string]string{
    42  			typeKey:          sqlException,
    43  			sourceKey:        telemetrySource,
    44  			driverTypeKey:    "Go",
    45  			driverVersionKey: SnowflakeGoDriverVersion,
    46  			stacktraceKey:    maskSecrets(string(debug.Stack())),
    47  		},
    48  		Timestamp: time.Now().UnixNano() / int64(time.Millisecond),
    49  	}
    50  	if se.QueryID != "" {
    51  		data.Message[queryIDKey] = se.QueryID
    52  	}
    53  	if se.SQLState != "" {
    54  		data.Message[sqlStateKey] = se.SQLState
    55  	}
    56  	if se.Message != "" {
    57  		data.Message[reasonKey] = se.Message
    58  	}
    59  	if len(se.MessageArgs) > 0 {
    60  		data.Message[reasonKey] = fmt.Sprintf(se.Message, se.MessageArgs...)
    61  	}
    62  	if se.Number != 0 {
    63  		data.Message[errorNumberKey] = strconv.Itoa(se.Number)
    64  	}
    65  	return data
    66  }
    67  
    68  func (se *SnowflakeError) sendExceptionTelemetry(sc *snowflakeConn, data *telemetryData) error {
    69  	if sc != nil && sc.telemetry != nil {
    70  		return sc.telemetry.addLog(data)
    71  	}
    72  	return nil // TODO oob telemetry
    73  }
    74  
    75  func (se *SnowflakeError) exceptionTelemetry(sc *snowflakeConn) *SnowflakeError {
    76  	data := se.generateTelemetryExceptionData()
    77  	if err := se.sendExceptionTelemetry(sc, data); err != nil {
    78  		logger.Debugf("failed to log to telemetry: %v", data)
    79  	}
    80  	return se
    81  }
    82  
    83  // return populated error fields replacing the default response
    84  func populateErrorFields(code int, data *execResponse) *SnowflakeError {
    85  	err := errUnknownError()
    86  	if code != -1 {
    87  		err.Number = code
    88  	}
    89  	if data.Data.SQLState != "" {
    90  		err.SQLState = data.Data.SQLState
    91  	}
    92  	if data.Message != "" {
    93  		err.Message = data.Message
    94  	}
    95  	if data.Data.QueryID != "" {
    96  		err.QueryID = data.Data.QueryID
    97  	}
    98  	return err
    99  }
   100  
   101  const (
   102  	/* connection */
   103  
   104  	// ErrCodeEmptyAccountCode is an error code for the case where a DNS doesn't include account parameter
   105  	ErrCodeEmptyAccountCode = 260000
   106  	// ErrCodeEmptyUsernameCode is an error code for the case where a DNS doesn't include user parameter
   107  	ErrCodeEmptyUsernameCode = 260001
   108  	// ErrCodeEmptyPasswordCode is an error code for the case where a DNS doesn't include password parameter
   109  	ErrCodeEmptyPasswordCode = 260002
   110  	// ErrCodeFailedToParseHost is an error code for the case where a DNS includes an invalid host name
   111  	ErrCodeFailedToParseHost = 260003
   112  	// ErrCodeFailedToParsePort is an error code for the case where a DNS includes an invalid port number
   113  	ErrCodeFailedToParsePort = 260004
   114  	// ErrCodeIdpConnectionError is an error code for the case where a IDP connection failed
   115  	ErrCodeIdpConnectionError = 260005
   116  	// ErrCodeSSOURLNotMatch is an error code for the case where a SSO URL doesn't match
   117  	ErrCodeSSOURLNotMatch = 260006
   118  	// ErrCodeServiceUnavailable is an error code for the case where service is unavailable.
   119  	ErrCodeServiceUnavailable = 260007
   120  	// ErrCodeFailedToConnect is an error code for the case where a DB connection failed due to wrong account name
   121  	ErrCodeFailedToConnect = 260008
   122  	// ErrCodeRegionOverlap is an error code for the case where a region is specified despite an account region present
   123  	ErrCodeRegionOverlap = 260009
   124  	// ErrCodePrivateKeyParseError is an error code for the case where the private key is not parsed correctly
   125  	ErrCodePrivateKeyParseError = 260010
   126  	// ErrCodeFailedToParseAuthenticator is an error code for the case where a DNS includes an invalid authenticator
   127  	ErrCodeFailedToParseAuthenticator = 260011
   128  	// ErrCodeClientConfigFailed is an error code for the case where clientConfigFile is invalid or applying client configuration fails
   129  	ErrCodeClientConfigFailed = 260012
   130  
   131  	/* network */
   132  
   133  	// ErrFailedToPostQuery is an error code for the case where HTTP POST failed.
   134  	ErrFailedToPostQuery = 261000
   135  	// ErrFailedToRenewSession is an error code for the case where session renewal failed.
   136  	ErrFailedToRenewSession = 261001
   137  	// ErrFailedToCancelQuery is an error code for the case where cancel query failed.
   138  	ErrFailedToCancelQuery = 261002
   139  	// ErrFailedToCloseSession is an error code for the case where close session failed.
   140  	ErrFailedToCloseSession = 261003
   141  	// ErrFailedToAuth is an error code for the case where authentication failed for unknown reason.
   142  	ErrFailedToAuth = 261004
   143  	// ErrFailedToAuthSAML is an error code for the case where authentication via SAML failed for unknown reason.
   144  	ErrFailedToAuthSAML = 261005
   145  	// ErrFailedToAuthOKTA is an error code for the case where authentication via OKTA failed for unknown reason.
   146  	ErrFailedToAuthOKTA = 261006
   147  	// ErrFailedToGetSSO is an error code for the case where authentication via OKTA failed for unknown reason.
   148  	ErrFailedToGetSSO = 261007
   149  	// ErrFailedToParseResponse is an error code for when we cannot parse an external browser response from Snowflake.
   150  	ErrFailedToParseResponse = 261008
   151  	// ErrFailedToGetExternalBrowserResponse is an error code for when there's an error reading from the open socket.
   152  	ErrFailedToGetExternalBrowserResponse = 261009
   153  	// ErrFailedToHeartbeat is an error code when a heartbeat fails.
   154  	ErrFailedToHeartbeat = 261010
   155  
   156  	/* rows */
   157  
   158  	// ErrFailedToGetChunk is an error code for the case where it failed to get chunk of result set
   159  	ErrFailedToGetChunk = 262000
   160  
   161  	/* transaction*/
   162  
   163  	// ErrNoReadOnlyTransaction is an error code for the case where readonly mode is specified.
   164  	ErrNoReadOnlyTransaction = 263000
   165  	// ErrNoDefaultTransactionIsolationLevel is an error code for the case where non default isolation level is specified.
   166  	ErrNoDefaultTransactionIsolationLevel = 263001
   167  
   168  	/* file transfer */
   169  
   170  	// ErrInvalidStageFs is an error code denoting an invalid stage in the file system
   171  	ErrInvalidStageFs = 264001
   172  	// ErrFailedToDownloadFromStage is an error code denoting the failure to download a file from the stage
   173  	ErrFailedToDownloadFromStage = 264002
   174  	// ErrFailedToUploadToStage is an error code denoting the failure to upload a file to the stage
   175  	ErrFailedToUploadToStage = 264003
   176  	// ErrInvalidStageLocation is an error code denoting an invalid stage location
   177  	ErrInvalidStageLocation = 264004
   178  	// ErrLocalPathNotDirectory is an error code denoting a local path that is not a directory
   179  	ErrLocalPathNotDirectory = 264005
   180  	// ErrFileNotExists is an error code denoting the file to be transferred does not exist
   181  	ErrFileNotExists = 264006
   182  	// ErrCompressionNotSupported is an error code denoting the user specified compression type is not supported
   183  	ErrCompressionNotSupported = 264007
   184  	// ErrInternalNotMatchEncryptMaterial is an error code denoting the encryption material specified does not match
   185  	ErrInternalNotMatchEncryptMaterial = 264008
   186  	// ErrCommandNotRecognized is an error code denoting the PUT/GET command was not recognized
   187  	ErrCommandNotRecognized = 264009
   188  	// ErrFailedToConvertToS3Client is an error code denoting the failure of an interface to s3.Client conversion
   189  	ErrFailedToConvertToS3Client = 264010
   190  	// ErrNotImplemented is an error code denoting the file transfer feature is not implemented
   191  	ErrNotImplemented = 264011
   192  	// ErrInvalidPadding is an error code denoting the invalid padding of decryption key
   193  	ErrInvalidPadding = 264012
   194  
   195  	/* binding */
   196  
   197  	// ErrBindSerialization is an error code for a failed serialization of bind variables
   198  	ErrBindSerialization = 265001
   199  	// ErrBindUpload is an error code for the uploading process of bind elements to the stage
   200  	ErrBindUpload = 265002
   201  
   202  	/* async */
   203  
   204  	// ErrAsync is an error code for an unknown async error
   205  	ErrAsync = 266001
   206  
   207  	/* multi-statement */
   208  
   209  	// ErrNoResultIDs is an error code for empty result IDs for multi statement queries
   210  	ErrNoResultIDs = 267001
   211  
   212  	/* converter */
   213  
   214  	// ErrInvalidTimestampTz is an error code for the case where a returned TIMESTAMP_TZ internal value is invalid
   215  	ErrInvalidTimestampTz = 268000
   216  	// ErrInvalidOffsetStr is an error code for the case where a offset string is invalid. The input string must
   217  	// consist of sHHMI where one sign character '+'/'-' followed by zero filled hours and minutes
   218  	ErrInvalidOffsetStr = 268001
   219  	// ErrInvalidBinaryHexForm is an error code for the case where a binary data in hex form is invalid.
   220  	ErrInvalidBinaryHexForm = 268002
   221  	// ErrTooHighTimestampPrecision is an error code for the case where cannot convert Snowflake timestamp to arrow.Timestamp
   222  	ErrTooHighTimestampPrecision = 268003
   223  
   224  	/* OCSP */
   225  
   226  	// ErrOCSPStatusRevoked is an error code for the case where the certificate is revoked.
   227  	ErrOCSPStatusRevoked = 269001
   228  	// ErrOCSPStatusUnknown is an error code for the case where the certificate revocation status is unknown.
   229  	ErrOCSPStatusUnknown = 269002
   230  	// ErrOCSPInvalidValidity is an error code for the case where the OCSP response validity is invalid.
   231  	ErrOCSPInvalidValidity = 269003
   232  	// ErrOCSPNoOCSPResponderURL is an error code for the case where the OCSP responder URL is not attached.
   233  	ErrOCSPNoOCSPResponderURL = 269004
   234  
   235  	/* query Status*/
   236  
   237  	// ErrQueryStatus when check the status of a query, receive error or no status
   238  	ErrQueryStatus = 279001
   239  	// ErrQueryIDFormat the query ID given to fetch its result is not valid
   240  	ErrQueryIDFormat = 279101
   241  	// ErrQueryReportedError server side reports the query failed with error
   242  	ErrQueryReportedError = 279201
   243  	// ErrQueryIsRunning the query is still running
   244  	ErrQueryIsRunning = 279301
   245  
   246  	/* GS error code */
   247  
   248  	// ErrSessionGone is an GS error code for the case that session is already closed
   249  	ErrSessionGone = 390111
   250  	// ErrRoleNotExist is a GS error code for the case that the role specified does not exist
   251  	ErrRoleNotExist = 390189
   252  	// ErrObjectNotExistOrAuthorized is a GS error code for the case that the server-side object specified does not exist
   253  	ErrObjectNotExistOrAuthorized = 390201
   254  )
   255  
   256  const (
   257  	errMsgFailedToParseHost                  = "failed to parse a host name. host: %v"
   258  	errMsgFailedToParsePort                  = "failed to parse a port number. port: %v"
   259  	errMsgFailedToParseAuthenticator         = "failed to parse an authenticator: %v"
   260  	errMsgInvalidOffsetStr                   = "offset must be a string consist of sHHMI where one sign character '+'/'-' followed by zero filled hours and minutes: %v"
   261  	errMsgInvalidByteArray                   = "invalid byte array: %v"
   262  	errMsgIdpConnectionError                 = "failed to verify URLs. authenticator: %v, token URL:%v, SSO URL:%v"
   263  	errMsgSSOURLNotMatch                     = "SSO URL didn't match. expected: %v, got: %v"
   264  	errMsgFailedToGetChunk                   = "failed to get a chunk of result sets. idx: %v"
   265  	errMsgFailedToPostQuery                  = "failed to POST. HTTP: %v, URL: %v"
   266  	errMsgFailedToRenew                      = "failed to renew session. HTTP: %v, URL: %v"
   267  	errMsgFailedToCancelQuery                = "failed to cancel query. HTTP: %v, URL: %v"
   268  	errMsgFailedToCloseSession               = "failed to close session. HTTP: %v, URL: %v"
   269  	errMsgFailedToAuth                       = "failed to auth for unknown reason. HTTP: %v, URL: %v"
   270  	errMsgFailedToAuthSAML                   = "failed to auth via SAML for unknown reason. HTTP: %v, URL: %v"
   271  	errMsgFailedToAuthOKTA                   = "failed to auth via OKTA for unknown reason. HTTP: %v, URL: %v"
   272  	errMsgFailedToGetSSO                     = "failed to auth via OKTA for unknown reason. HTTP: %v, URL: %v"
   273  	errMsgFailedToParseResponse              = "failed to parse a response from Snowflake. Response: %v"
   274  	errMsgFailedToGetExternalBrowserResponse = "failed to get an external browser response from Snowflake, err: %s"
   275  	errMsgNoReadOnlyTransaction              = "no readonly mode is supported"
   276  	errMsgNoDefaultTransactionIsolationLevel = "no default isolation transaction level is supported"
   277  	errMsgServiceUnavailable                 = "service is unavailable. check your connectivity. you may need a proxy server. HTTP: %v, URL: %v"
   278  	errMsgFailedToConnect                    = "failed to connect to db. verify account name is correct. HTTP: %v, URL: %v"
   279  	errMsgOCSPStatusRevoked                  = "OCSP revoked: reason:%v, at:%v"
   280  	errMsgOCSPStatusUnknown                  = "OCSP unknown"
   281  	errMsgOCSPInvalidValidity                = "invalid validity: producedAt: %v, thisUpdate: %v, nextUpdate: %v"
   282  	errMsgOCSPNoOCSPResponderURL             = "no OCSP server is attached to the certificate. %v"
   283  	errMsgBindColumnMismatch                 = "column %v has a different number of binds (%v) than column 1 (%v)"
   284  	errMsgNotImplemented                     = "not implemented"
   285  	errMsgFeatureNotSupported                = "feature is not supported: %v"
   286  	errMsgCommandNotRecognized               = "%v command not recognized"
   287  	errMsgLocalPathNotDirectory              = "the local path is not a directory: %v"
   288  	errMsgFileNotExists                      = "file does not exist: %v"
   289  	errMsgInvalidStageFs                     = "destination location type is not valid: %v"
   290  	errMsgInternalNotMatchEncryptMaterial    = "number of downloading files doesn't match the encryption materials. files=%v, encmat=%v"
   291  	errMsgFailedToConvertToS3Client          = "failed to convert interface to s3 client"
   292  	errMsgNoResultIDs                        = "no result IDs returned with the multi-statement query"
   293  	errMsgQueryStatus                        = "server ErrorCode=%s, ErrorMessage=%s"
   294  	errMsgInvalidPadding                     = "invalid padding on input"
   295  	errMsgClientConfigFailed                 = "client configuration failed: %v"
   296  )
   297  
   298  // Returned if a DNS doesn't include account parameter.
   299  func errEmptyAccount() *SnowflakeError {
   300  	return &SnowflakeError{
   301  		Number:  ErrCodeEmptyAccountCode,
   302  		Message: "account is empty",
   303  	}
   304  }
   305  
   306  // Returned if a DNS doesn't include user parameter.
   307  func errEmptyUsername() *SnowflakeError {
   308  	return &SnowflakeError{
   309  		Number:  ErrCodeEmptyUsernameCode,
   310  		Message: "user is empty",
   311  	}
   312  }
   313  
   314  // Returned if a DNS doesn't include password parameter.
   315  func errEmptyPassword() *SnowflakeError {
   316  	return &SnowflakeError{
   317  		Number:  ErrCodeEmptyPasswordCode,
   318  		Message: "password is empty",
   319  	}
   320  }
   321  
   322  // Returned if a DSN's implicit region from account parameter and explicit region parameter conflict.
   323  func errInvalidRegion() *SnowflakeError {
   324  	return &SnowflakeError{
   325  		Number:  ErrCodeRegionOverlap,
   326  		Message: "two regions specified",
   327  	}
   328  }
   329  
   330  // Returned if a DSN includes an invalid authenticator.
   331  func errFailedToParseAuthenticator() *SnowflakeError {
   332  	return &SnowflakeError{
   333  		Number:  ErrCodeFailedToParseAuthenticator,
   334  		Message: "failed to parse an authenticator",
   335  	}
   336  }
   337  
   338  // Returned if the server side returns an error without meaningful message.
   339  func errUnknownError() *SnowflakeError {
   340  	return &SnowflakeError{
   341  		Number:   -1,
   342  		SQLState: "-1",
   343  		Message:  "an unknown server side error occurred",
   344  		QueryID:  "-1",
   345  	}
   346  }