views:

35

answers:

1

Is it possible to edit the data returned from command.ExecuteReader, and then return that to SqlContext.Pipe.Send()? Are there any forseeable issues (I have to reset the cursor to the beginning)?

I have a .NET stored procedure that will query a table like this

(code from MSDN)

public class StoredProcedures 
{
   /// <summary>
   /// Execute a command and send the resulting reader to the client
   /// </summary>
   [Microsoft.SqlServer.Server.SqlProcedure]
   public static void SendReaderToClient()
   {
      using(SqlConnection connection = new SqlConnection("context connection=true")) 
      {
         connection.Open();
         SqlCommand command = new SqlCommand("select FirstName,LastName, PictureURL from myTable", connection);
         SqlDataReader r = command.ExecuteReader();
         //QUESTION: Can I modify "r" here, and return it below?
         SqlContext.Pipe.Send(r);
      }
   }
}
+1  A: 

You can describe your own result set with SendResultStart, then send each row with SendResultsRow:

  using(SqlConnection connection = new SqlConnection("context connection=true")) 
  {
     // Create the record and specify the metadata for the columns.
     // This record describes a result with two columns:
     //  Name NVARCHAR(4000)
     //  URL VARCHAR(4000)
     //
     SqlDataRecord record = new SqlDataRecord(
       new SqlMetaData("Name", SqlDbType.NVarChar, 4000),
       new SqlMetaData("URL", SqlDbType.VarChar, 4000),
       ...);

     // Mark the begining of the result-set.
     SqlContext.Pipe.SendResultsStart(record);

     connection.Open();
     SqlCommand command = new SqlCommand("select Name, Picture from myTable", connection);
     using (SqlDataReader rdr = command.ExecuteReader())
     {
        while(rdr.Read ())
        {
            // Transform the current row from rdr into the target record
            string nameDb = rdr.GetString(0);
            string urlDb = rdr.GetString(1);

            // do the transformations:
            string nameResult = String.Format("<h2>{0}</h2>", nameDb);
            string awt = ComputeTheAWT(urlDb);
            string urlResult = FormatURL (urlDb, awt);

            // Assign the record properties
            record.SetString(0, nameResult);
            record.SetString(1, urlResult);

            // send the record
            SqlContext.Pipe.SendResultsRow(record);
        }
     }
     SqlContext.Pipe.SendResultsEnd ();
  }
Remus Rusanu
Thank you I'm a little confused by the ellipsis... perhaps it's because I have select * in my code. I added some fake columns, where I'll wrap the name in "h2" tags, and the Url with img src="" tags
MakerOfThings7
The kind of transformation you mention is much easier done straight in the query, as in `SELECT '<h2>' + Name + '</h2>'...`
Remus Rusanu
Well, I was simplifying the example. In truth I'll be reading the string and appending an MD5 hash to the URL for access control purposes.
MakerOfThings7
That's still no reason for CLR. use `HASHBYTES`: http://msdn.microsoft.com/en-us/library/ms174415.aspx
Remus Rusanu
I was writing in the comments section so I kept it short. The resulting string will be URL + "?" + SWT (not really a hash), where SWT is the PKI encrypted 1) Expiration of the request + (2) Target URL from DB + (3) PKI signature of all 3 elements (as a hash). Very similar to Microsoft Azure ACS 'SWT' format. I may include a 4th element that contains the rights (Read, Write, Delete, etc) as claims
MakerOfThings7
And if you're wondering why I'm implementing this in the Sproc, it's because Cognos doesn't give us many options in the scenario we are attempting
MakerOfThings7
.. and to put the whole picture together, the client (passive web browser) will do a GET against a WCF service like this: http://stackoverflow.com/questions/3937766/reading-a-file-from-a-unc-path-and-setting-the-correct-mime-type-in-a-http-reques where I'll decrypt the SWT and validate access to the given file. If the signature is invalid, date is expired,or access type doesn't match then deny the request.
MakerOfThings7
See my edit, perhaps now is more clear how the `SqlDataRecord` object is used.
Remus Rusanu
Thanks Remus!!!
MakerOfThings7