-
Notifications
You must be signed in to change notification settings - Fork 426
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Server Message Handler and SQLException Chaining #2251
Changes from all commits
1950089
3d08589
7d4c801
f4c996b
e98188b
e81caf3
7a0edc3
3ddac91
8f6fa89
9e984fd
50a72ce
4ba63c6
157394a
9298439
73c6ad7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
/* | ||
* Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made | ||
* available under the terms of the MIT License. See the LICENSE file in the project root for more information. | ||
*/ | ||
package com.microsoft.sqlserver.jdbc; | ||
|
||
import java.sql.SQLException; | ||
|
||
public interface ISQLServerMessage | ||
{ | ||
/** | ||
* Returns SQLServerError containing detailed info about SQL Server Message as received from SQL Server. | ||
* | ||
* @return SQLServerError | ||
*/ | ||
public SQLServerError getSQLServerMessage(); | ||
|
||
/** | ||
* Returns error message as received from SQL Server | ||
* | ||
* @return Error Message | ||
*/ | ||
public String getErrorMessage(); | ||
|
||
/** | ||
* Returns error number as received from SQL Server | ||
* | ||
* @return Error Number | ||
*/ | ||
public int getErrorNumber(); | ||
|
||
/** | ||
* Returns error state as received from SQL Server | ||
* | ||
* @return Error State | ||
*/ | ||
public int getErrorState(); | ||
|
||
/** | ||
* Returns Severity of error (as int value) as received from SQL Server | ||
* | ||
* @return Error Severity | ||
*/ | ||
public int getErrorSeverity(); | ||
|
||
/** | ||
* Returns name of the server where exception occurs as received from SQL Server | ||
* | ||
* @return Server Name | ||
*/ | ||
public String getServerName(); | ||
|
||
/** | ||
* Returns name of the stored procedure where exception occurs as received from SQL Server | ||
* | ||
* @return Procedure Name | ||
*/ | ||
public String getProcedureName(); | ||
|
||
/** | ||
* Returns line number where the error occurred in Stored Procedure returned by <code>getProcedureName()</code> as | ||
* received from SQL Server | ||
* | ||
* @return Line Number | ||
*/ | ||
public long getLineNumber(); | ||
|
||
/** | ||
* Creates a SQLServerException or SQLServerWarning from this SQLServerMessage<br> | ||
* @return | ||
* <ul> | ||
* <li>SQLServerException if it's a SQLServerError object</li> | ||
* <li>SQLServerWarning if it's a SQLServerInfoMessage object</li> | ||
* </ul> | ||
*/ | ||
public SQLException toSqlExceptionOrSqlWarning(); | ||
|
||
/** | ||
* Check if this is a isErrorMessage | ||
* @return true if it's an instance of SQLServerError | ||
*/ | ||
public default boolean isErrorMessage() { | ||
return this instanceof SQLServerError; | ||
} | ||
|
||
/** | ||
* Check if this is a SQLServerInfoMessage | ||
* @return true if it's an instance of SQLServerInfoMessage | ||
*/ | ||
public default boolean isInfoMessage() { | ||
return this instanceof SQLServerInfoMessage; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
/* | ||
* Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made | ||
* available under the terms of the MIT License. See the LICENSE file in the project root for more information. | ||
*/ | ||
package com.microsoft.sqlserver.jdbc; | ||
|
||
/** | ||
* You can use the ISQLServerMessageHandler interface to customize the way JDBC handles error messages generated by the SQL Server. | ||
* Implementing ISQLServerMessageHandler in your own class for handling error messages can provide the following benefits: | ||
* <ul> | ||
* <li><b>"message feedback"</b><br> | ||
* Display Server messages from a long running SQL Statement<br> | ||
* Like <code>RAISERROR ('Progress message...', 0, 1) WITH NOWAIT</code><br> | ||
* Or Status messages from a running backup...<br> | ||
* </li> | ||
* <li><b>"Universal" error logging</b><br> | ||
* Your error-message handler can contain the logic for handling all error logging. | ||
* </li> | ||
* <li><b>"Universal" error handling</b><br> | ||
* Error-handling logic can be placed in your error-message handler, instead of being repeated throughout your application. | ||
* </li> | ||
* <li><b>Remapping of error-message severity</b>, based on application requirements<br> | ||
* Your error-message handler can contain logic for recognizing specific error messages, and downgrading or upgrading | ||
* their severity based on application considerations rather than the severity rating of the server. | ||
* For example, during a cleanup operation that deletes old rows, you might want to downgrade the severity of a | ||
* message that a row does not exist. However, you may want to upgrade the severity in other circumstances. | ||
* </li> | ||
* </ul> | ||
* <p> | ||
* For example code, see {@link #messageHandler(ISQLServerMessage)} | ||
*/ | ||
public interface ISQLServerMessageHandler | ||
{ | ||
/** | ||
* You can use the ISQLServerMessageHandler interface to customize the way JDBC handles error messages generated by the SQL Server. | ||
* Implementing ISQLServerMessageHandler in your own class for handling error messages can provide the following benefits: | ||
* <ul> | ||
* <li><b>"message feedback"</b><br> | ||
* Display Server messages from a long running SQL Statement<br> | ||
* Like <code>RAISERROR ('Progress message...', 0, 1) WITH NOWAIT</code><br> | ||
* Or Status messages from a running backup...<br> | ||
* </li> | ||
* <li><b>"Universal" error logging</b><br> | ||
* Your error-message handler can contain the logic for handling all error logging. | ||
* </li> | ||
* <li><b>"Universal" error handling</b><br> | ||
* Error-handling logic can be placed in your error-message handler, instead of being repeated throughout your application. | ||
* </li> | ||
* <li><b>Remapping of error-message severity</b>, based on application requirements<br> | ||
* Your error-message handler can contain logic for recognizing specific error messages, and downgrading or upgrading | ||
* their severity based on application considerations rather than the severity rating of the server. | ||
* For example, during a cleanup operation that deletes old rows, you might want to downgrade the severity of a | ||
* message that a row does not exist. However, you may want to upgrade the severity in other circumstances. | ||
* </li> | ||
* </ul> | ||
* | ||
* Example code: | ||
* <pre> | ||
* public ISQLServerMessage messageHandler(ISQLServerMessage serverErrorOrWarning) | ||
* { | ||
* ISQLServerMessage retObj = serverErrorOrWarning; | ||
* | ||
* if (serverErrorOrWarning.isErrorMessage()) { | ||
* | ||
* // Downgrade: 2601 -- Cannot insert duplicate key row... | ||
* if (2601 == serverErrorOrWarning.getErrorNumber()) { | ||
* retObj = serverErrorOrWarning.getSQLServerMessage().toSQLServerInfoMessage(); | ||
* } | ||
* | ||
* // Discard: 3701 -- Cannot drop the table ... | ||
* if (3701 == serverErrorOrWarning.getErrorNumber()) { | ||
* retObj = null; | ||
* } | ||
* } | ||
* | ||
* return retObj; | ||
* } | ||
|
||
* </pre> | ||
* | ||
* @param serverErrorOrWarning | ||
* @return | ||
* <ul> | ||
* <li><b>unchanged</b> same object as passed in.<br> | ||
* The JDBC driver will works as if no message hander was installed<br> | ||
* Possibly used for logging functionality<br> | ||
* </li> | ||
* <li><b>null</b><br> | ||
* The JDBC driver will <i>discard</i> this message. No SQLException will be thrown | ||
* </li> | ||
* <li><b>SQLServerInfoMessage</b> object<br> | ||
* Create a "SQL warning" from a input database error, and return it. | ||
* This results in the warning being added to the warning-message chain. | ||
* </li> | ||
* <li><b>SQLServerError</b> object<br> | ||
* If the originating message is a SQL warning (SQLServerInfoMessage object), messageHandler can evaluate | ||
* the SQL warning as urgent and create and return a SQL exception (SQLServerError object) | ||
* to be thrown once control is returned to the JDBC Driver. | ||
* </li> | ||
* </ul> | ||
*/ | ||
ISQLServerMessage messageHandler(ISQLServerMessage serverErrorOrWarning); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4928,6 +4928,27 @@ void addWarning(String warningString) { | |
} | ||
} | ||
|
||
// Any changes to SQLWarnings should be synchronized. | ||
/** Used to add plain SQLWarning messages (if they do not hold extended information, like: ErrorSeverity, ServerName, ProcName etc */ | ||
void addWarning(SQLWarning sqlWarning) { | ||
warningSynchronization.lock(); | ||
try { | ||
if (null == sqlWarnings) { | ||
sqlWarnings = sqlWarning; | ||
} else { | ||
sqlWarnings.setNextWarning(sqlWarning); | ||
} | ||
} finally { | ||
warningSynchronization.unlock(); | ||
} | ||
} | ||
|
||
// Any changes to SQLWarnings should be synchronized. | ||
/** Used to add messages that holds extended information, like: ErrorSeverity, ServerName, ProcName etc */ | ||
void addWarning(ISQLServerMessage sqlServerMessage) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. since we now have 2 of these, add comment on how they differ and how they are used There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
addWarning(new SQLServerWarning(sqlServerMessage.getSQLServerMessage())); | ||
} | ||
|
||
@Override | ||
public void clearWarnings() throws SQLServerException { | ||
warningSynchronization.lock(); | ||
|
@@ -8500,6 +8521,34 @@ public void setIPAddressPreference(String iPAddressPreference) { | |
public String getIPAddressPreference() { | ||
return activeConnectionProperties.getProperty(SQLServerDriverStringProperty.IPADDRESS_PREFERENCE.toString()); | ||
} | ||
|
||
|
||
|
||
/** Message handler */ | ||
private transient ISQLServerMessageHandler serverMessageHandler; | ||
|
||
/** | ||
* Set current message handler | ||
* | ||
* @param messageHandler | ||
* @return The previously installed message handler (null if none) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why does the setter need to return anything? there is already a getter There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is just convenience... For example the java Properties.getProperty("someName") does the same thing! |
||
*/ | ||
@Override | ||
public ISQLServerMessageHandler setServerMessageHandler(ISQLServerMessageHandler messageHandler) | ||
{ | ||
ISQLServerMessageHandler installedMessageHandler = this.serverMessageHandler; | ||
this.serverMessageHandler = messageHandler; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this overwrites any existing, maybe should check and log a message? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes a setter usually overwrites previous values... If you want: I can generate a log message (let me know the LogLevel) |
||
return installedMessageHandler; | ||
} | ||
|
||
/** | ||
* @return Get Currently installed message handler on the connection | ||
*/ | ||
@Override | ||
public ISQLServerMessageHandler getServerMessageHandler() | ||
{ | ||
return this.serverMessageHandler; | ||
} | ||
} | ||
|
||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
javadoc class description
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done