AdoNetCore.AseClient: AseConnection.InfoMessage is currently never triggered

When I issue the following command to an ASE

LOAD DATABASE AZU WITH LISTONLY=LOAD_SQL,UNTIL_TIME='2018-08-16T17:40:23:310'

it returns a SQL script which I could use to restore a database to a particular point in time. The problem is that the response is not a result set or so, but just informational messages.

I subscribed to AseConnection.InfoMessage, but the private AseConnection.NotifyInfoMessage() method is never triggered… The event InfoMessageInternal has a TODO flag 😃.

What would be the best / desired way to implement that functionality? InternalConnection.InternalExecuteAsync() looks like a place where the command.Connection could be passed down to the MessageTokenHandler to fire this event.

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Comments: 19 (7 by maintainers)

Most upvoted comments

the type AseInfoMessageEventArgs has an interesting interpretation of what it should be doing… it has 2 properties:

  • AseInfoMessageEventArgs.Errors is never null, it may contain 0 results though. It contains all? the TDS_EED messages from the response stream in the sequence they arrive.
  • AseInfoMessageEventArgs.Message always returns the value of Errors[0].Message and thus may potentially throw an index out of bounds error (in practice I don’t think this ever happens because I hope the driver only ever raises the event when Errors has at least one element; regardless you should not treat .Message as a safe property to rely on)

My suggestion for the classes would be something like

public class AseInfoMessageEventArgs : EventArgs
{
    [NotNull]
    public AseErrorCollection Errors { get; }
    public string Message => Errors.FirstOrDefault()?.Message;

    internal AseInfoMessageEventArgs(AseErrorCollection errors) => Errors = errors;
}

public class AseErrorCollection : ReadOnlyCollection<AseError>
{
    internal AseErrorCollection([NotNull][ItemNotNull] IList<AseError> list) : base(list) { }
}

Our reference driver places all messages inside the AseInfoMessageEventArgs.Errors property… adapted from my production logging code:

void captureResult(object sender, AseInfoMessageEventArgs aseInfoMessageEventArgs) {
    foreach (AseError error in aseInfoMessageEventArgs.Errors) {
        result.Add("\nMessage: " + error.Message +
                   "\nErr Number: " + error.MessageNumber +
                   "\nSQLState: " + error.SqlState +
                   "\nSeverity: " + error.Severity +
                   "\nIsError: " + error.IsError +
                   "\nIsFromServer: " + error.IsFromServer +
                   "\nIsFromClient: " + error.IsFromClient +
                   "\nIsInformation: " + error.IsInformation +
                   "\nIsWarning: " + error.IsWarning +
                   "\nLineNum: " + error.LineNum +
                   "\nProcName: " + error.ProcName +
                   "\nServerName: " + error.ServerName +
                   "\nStatus: " + error.Status +
                   "\nTranState: " + error.TranState +
                   "\n----");
    }
}

outputs multiple lines:

Message: LOAD DATABASE [redacted]

Err Number: 3640
SQLState: ZZZZZ
Severity: 10
IsError: False
IsFromServer: True
IsFromClient: False
IsInformation: False
IsWarning: True
LineNum: 1
ProcName:
ServerName:  [redacted]
Status: 0
TranState: 1
----

(I am using the 16.0.3.0 driver; to get the latest you are supposed to have your dba log in to their portal and download the sdk)

Right. I just wanted to make sure you don’t mean some other DLL burried deep down in the ase_setup.zip or so 😃