@@ -40,21 +40,33 @@ class ConnectionErrorCode(Enum):
4040# Connection error messages, which we expect to get from an ADO provider or
4141# ODBC. These drivers can have inconsistent error codes across versions, so regex on
4242# the known error messages
43- known_error_patterns = {
43+ KNOWN_ERROR_PATTERNS = {
4444 # typically results in an -2147467259 ADO error code, which is not very descriptive. Identifying this error
4545 # can help provide specific troubleshooting help to the customer
46- "(certificate verify failed|"
47- "certificate chain was issued by an authority that is not trusted)" : ConnectionErrorCode .certificate_verify_failed ,
46+ re .compile (
47+ "(certificate verify failed|certificate chain was issued by an authority that is not trusted)" , re .IGNORECASE
48+ ): ConnectionErrorCode .certificate_verify_failed ,
4849 # DSN could be specified incorrectly in config
49- "data source name not found.* and no default driver specified" : ConnectionErrorCode .driver_not_found ,
50+ re .compile (
51+ "data source name not found.* and no default driver specified" , re .IGNORECASE
52+ ): ConnectionErrorCode .driver_not_found ,
5053 # driver not installed on host
51- "(can't open lib .* file not found|Provider cannot be found)" : ConnectionErrorCode .driver_not_found ,
54+ re .compile (
55+ "(can't open lib .* file not found|Provider cannot be found)" , re .IGNORECASE
56+ ): ConnectionErrorCode .driver_not_found ,
5257 # Connection & login issues
53- "(cannot open database .* requested by the login|login timeout expired)" : ConnectionErrorCode .tcp_connection_failed ,
54- "(login failed for user|The login is from an untrusted domain)" : ConnectionErrorCode .login_failed_for_user ,
55- "ssl security error" : ConnectionErrorCode .ssl_security_error ,
58+ re .compile (
59+ "(cannot open database .* requested by the login|login timeout expired)" , re .IGNORECASE
60+ ): ConnectionErrorCode .tcp_connection_failed ,
61+ re .compile (
62+ "(login failed for user|The login is from an untrusted domain)" , re .IGNORECASE
63+ ): ConnectionErrorCode .login_failed_for_user ,
64+ re .compile ("ssl security error" , re .IGNORECASE ): ConnectionErrorCode .ssl_security_error ,
5665}
5766
67+ # Pre-compiled regex pattern for password obfuscation
68+ PASSWORD_OBFUSCATION_PATTERN = re .compile (r"(?i)(Password=)([^;]+)" )
69+
5870# ADO provider connection errors yield a hresult code, which
5971# can be mapped to helpful err messages
6072known_hresult_codes = {
@@ -132,9 +144,9 @@ def _get_is_odbc_driver_installed(configured_driver):
132144
133145
134146def _lookup_conn_error_and_msg (hresult , msg ):
135- for k in known_error_patterns . keys ():
136- if re .search (k , msg , re . IGNORECASE ):
137- return None , known_error_patterns [ k ]
147+ for compiled_pattern , error_code in KNOWN_ERROR_PATTERNS . items ():
148+ if compiled_pattern .search (msg ):
149+ return None , error_code
138150 # if we cannot determine the type or error based on the msg, try to look it up by its hresult
139151 # this will be true for error messages like 'Invalid connection string attribute'
140152 if hresult :
@@ -151,7 +163,7 @@ def obfuscate_error_msg(msg, password):
151163 # obfuscate the password in the error message
152164 # regex to match the `Password=<password>;` in the connection string
153165 # and replace it with `Password=***;` (case insensitive)
154- obfuscated_error_msg = re .sub (r"(?i)(Password=)([^;]+)" , r"\1******" , msg )
166+ obfuscated_error_msg = PASSWORD_OBFUSCATION_PATTERN .sub (r"\1******" , msg )
155167 if password :
156168 # this is a fallback in case the password is not in the connection string
157169 obfuscated_error_msg = obfuscated_error_msg .replace (password , "*" * 6 )
0 commit comments