2

Is it possible to capture PRINT output from a T-SQL in ADO?

For example:

PRINT 'Before the thing'
SELECT * FROM sys.tables
PRINT 'After the thing'

Is it possible in ADO to receive these PRINT messages?

I tried connecting to the InfoMessage event, but it is never fired. (although ExecuteComplete is; which is nice)

ConnectionEvents

For your convenience here are all the events exposed by an ADO Connection object:

[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("00000402-0000-0010-8000-00AA006D2EA4")]
public interface IConnectionEvents
{
   void InfoMessage(Error pError, ref EventStatusEnum, Connection, pConnection);
   void BeginTransComplete(Integer TransactionLevel, Error pError, ref EventStatusEnum adStatus, Connection pConnection);
   void CommitTransComplete(Error pError, ref EventStatusEnum adStatus, Connection pConnection);
   void RollbackTransComplete(Error pError, ref EventStatusEnum adStatus, Connection pConnection);
   void WillExecute(ref string Source, ref CursorTypeEnum CursorType, ref LockTypeEnum LockType, ref Integer Options, ref EventStatusEnum adStatus, Command pCommand, _Recordset pRecordset, Connection pConnection);
   void ExecuteComplete(Integer RecordsAffected, Error pError, ref adStatus EventStatusEnum, Command pCommand, Recordset pRecordset, Connection pConnection);
   void WillConnect(ref string ConnectionString, ref string UserID, ref string Password, ref Integer Options, ref EventStatusEnum adStatus, Connection pConnection);
   void ConnectComplete(Error pError, ref EventStatusEnum adStatus, Connection pConnection);
   void Disconnect(ref EventStatusEnum adStatus, Connection pConnection);
}

PRINT results not reported through Errors

The result of PRINT statements do not appear in the Errors collection after the T-SQL completes.

Which is good, because i need the feedback real-time; not after the entire batch completes.

Pseudocode

Connection conn = new Connection();
conn.ConnectionString = connectionString;
conn.Open();

//Hook up events listener
ConnectionEvents ev = new ConnectionEvents();
Integer cookie = (conn as IConnectionPointContainer).FindConnectionPoint(DIID_ConnectionEvents).Advise(ev);

//run our sql batch
conn.Execute(sql, out recordsAffected, adCmdText);

//Disconnect events
(conn as IConnectionPointContainer).FindConnectionPoint(DIID_ConnectionEvents).Unadvise(cookie);

And the magic of COM is that you create an object to receive all the events:

public class ConnectionEvents: IConnectionEvents
{
   void InfoMessage(Error pError, ref EventStatusEnum, Connection, pConnection) 
   {
      Debugger.Break();
   }
   void BeginTransComplete(Integer TransactionLevel, Error pError, ref EventStatusEnum adStatus, Connection pConnection) {}
   void CommitTransComplete(Error pError, ref EventStatusEnum adStatus, Connection pConnection) {}
   void RollbackTransComplete(Error pError, ref EventStatusEnum adStatus, Connection pConnection) {}
   void WillExecute(ref string Source, ref CursorTypeEnum CursorType, ref LockTypeEnum LockType, ref Integer Options, ref EventStatusEnum adStatus, Command pCommand, _Recordset pRecordset, Connection pConnection) {}
   void ExecuteComplete(Integer RecordsAffected, Error pError, ref adStatus EventStatusEnum, Command pCommand, Recordset pRecordset, Connection pConnection) 
   {
      Debugger.Break();
   }
   void WillConnect(ref string ConnectionString, ref string UserID, ref string Password, ref Integer Options, ref EventStatusEnum adStatus, Connection pConnection) {}
   void ConnectComplete(Error pError, ref EventStatusEnum adStatus, Connection pConnection) {}
   void Disconnect(ref EventStatusEnum adStatus, Connection pConnection) {}
}

SQLOLEDB Provider keywords

I wondered if maybe there was a ConnectionString keyword that would enable messages.

Fortunately, you can ask an OLEDB provider all the connection string keywords it supports. Your OLEDB provider is an IDataInitialize object. Cast it to IDBProperties, and you can interrogate it for all the properties it supports:

  • Property Set DBPROPSET_DBINIT

    • DBPROP_AUTH_INTEGRATED: "Integrated Security": VT_BSTR
    • DBPROP_AUTH_PASSWORD: "Password": VT_BSTR
    • DBPROP_AUTH_PERSIST_SENSITIVE_AUTHINFO: "Persist Security Info": VT_BOOL
    • DBPROP_AUTH_USERID: "User ID": VT_BSTR
    • DBPROP_INIT_CATALOG: "Initial Catalog": VT_BSTR
    • DBPROP_INIT_DATASOURCE: "Data Source": VT_BSTR
    • DBPROP_INIT_HWND: "Window Handle": VT_I4
    • DBPROP_INIT_LCID: "Locale Identifier": VT_I4
    • DBPROP_INIT_PROMPT: "Prompt": VT_I2
    • DBPROP_INIT_PROVIDERSTRING: "Extended Properties": VT_BSTR
    • DBPROP_INIT_TIMEOUT: "Connect Timeout": VT_I4
    • DBPROP_INIT_GENERALTIMEOUT: "General Timeout": VT_I4
    • DBPROP_INIT_OLEDBSERVICES: "OLE DB Services": VT_I4
  • Property Set DBPROPSET_SQLSERVERDBINIT

    • SSPROP_INIT_CURRENTLANGUAGE: "Current Language": VT_BSTR
    • SSPROP_INIT_NETWORKADDRESS: "Network Address": VT_BSTR
    • SSPROP_INIT_NETWORKLIBRARY: "Network Library": VT_BSTR
    • SSPROP_INIT_USEPROCFORPREP: "Use Procedure for Prepare": VT_I4
    • SSPROP_INIT_AUTOTRANSLATE: "Auto Translate": VT_BOOL
    • SSPROP_INIT_PACKETSIZE: "Packet Size": VT_I4
    • SSPROP_INIT_APPNAME: "Application Name": VT_BSTR
    • SSPROP_INIT_WSID: "Workstation ID": VT_BSTR
    • SSPROP_INIT_FILENAME: "Initial File Name": VT_BSTR
    • SSPROP_INIT_ENCRYPT: "Use Encryption for Data": VT_BOOL
    • SSPROP_AUTH_REPL_SERVER_NAME: "Replication server name connect option": VT_BSTR
    • SSPROP_INIT_TAGCOLUMNCOLLATION: "Tag with column collation when possible": VT_BOOL

None seem related to opting-in to extra messages.

Must be possible, Query Analyzer does it.

Bonus Reading

Ian Boyd
  • 246,734
  • 253
  • 869
  • 1,219
  • 2
    Not an ado guy, but [ms support](https://support.microsoft.com/en-ae/help/194792/how-to-retrieve-values-in-sql-server-stored-procedures-with-ado) has the snippet *PRINT statements in SQL Server can also populate the ADO errors collection. However, PRINT statements are severity level zero (0) so, at least one RAISERROR statement is required in the stored procedure to retrieve a PRINT statement with ADO through the Errors collection.* – S3S Oct 30 '18 at 18:53
  • At least in C#, you've got to capture these [as an InfoMessage with an event](https://stackoverflow.com/questions/1880471/capture-stored-procedure-print-output-in-net). – Bacon Bits Oct 30 '18 at 19:14
  • @BaconBits I'm not actually in C# (or using ADO.net). I'm actually using native Win32; which means ADO. I transcoded it to a *C#-like* syntax to make it easier for people to read. – Ian Boyd Oct 30 '18 at 19:17
  • I'm pretty sure you have to tell the SQL driver to raise the InfoEvent on lower severity statements to make this work. In ADO.NET, the property is `FireInfoMessageEventOnUserErrors` on a `SqlConnection`. Not sure what the analog is on ADO, it's been a long time; but if I recall there is something similar. – Tim Oct 31 '18 at 02:43

0 Answers0