Keith Miller
Keith Miller

Reputation: 1768

Error returning SQL Server result set using ODBC

I am converting an existing app from Sybase to SQL Server 2008. The app uses ODBC to connect to the database. Simply changing the connection string has worked for most of the apps functionality but there is one bug that has me puzzled. I have created a simple example that shows the bug.

I have a stored procedure:

create procedure dbo.test_sel
as 
begin
  create table #cfg
  (
    Name  varchar(100) NULL,
    Dscr  varchar(50)  NULL
  )

  insert #cfg(Name, Dscr) 
  values('Config', 'Config description')

  select COUNT(*) as [Count] from #cfg

  return 0
end

and code that executes the stored procedure and loads the results into a DataTable:

{
    OdbcCommand cmd = new OdbcCommand("test_sel", new OdbcConnection("Driver={SQL Server};Server=xxx;Database=xxx;Uid=xxx;Pwd=xxx"));

    DataTable dt = new DataTable();

    OdbcDataAdapter da = new OdbcDataAdapter(cmd);

    using (cmd.Connection)
    {
        da.Fill(dt);
    }

    MessageBox.Show(dt.Rows.Count.ToString());
}

I would expect the message to show the value 1 and the DataTable to contain a single row. However the DataTable is empty (no result set is returned).

Now, if I comment out the insert statement in the stored procedure and rerun the code then I do get a result set returned containing one row, one column named count with a value of 0.

I have tried many variants of the stored procedure, using a permanent table rather than temporary, for example but each time the same thing happens - having the insert stops the stored procedure from returning a result set.

Changing the ODBC driver to SQL Server 2008 makes no difference. The code works as expected when using Sybase and when run in the MS SQL Server Management Studio.

After a google search I tried the following code:

{
    SqlCommand cmd = new SqlCommand("test_sel", new SqlConnection("Server=xxx,5100;Database=xxx;User ID=xxx;Password=xxx"));

    DataTable dt = new DataTable();

    SqlDataAdapter da = new SqlDataAdapter(cmd);

    using (cmd.Connection)
    {
        da.Fill(dt);
    }

    MessageBox.Show(dt.Rows.Count.ToString());
}

Now this works but I would rather not make code changes for this if I can help it because the app needs to work on both databases.

Can anyone suggest why the original code does not work? It really seems like something that simple should work OK.

Upvotes: 1

Views: 1497

Answers (1)

Ivan Golović
Ivan Golović

Reputation: 8832

There are 2 options you can use to make this work (to me this seems like bug since Fill for both OdbcDataAdapter and SqlDataAdapter should work equally):

1) in the beginning of the procedure after the begin keyword add

set nocount on

2) Use the overload of Fill method that takes DataSet as parameter rather then the one that takes DataTable.

MSDN states: The overload of Fill that takes DataTable as a parameter only obtains the first result.

When INSERT is executed and NOCOUNT is off, information on how many rows were affected by the statement gets returned. So when you have this option off, count of rows will be reported 2 times (you can check that in SSMS, 'Messages' window), once for INSERT, second time for SELECT. It seems that first row count (from INSERT) somehow gets interpreted as first result set, this row count refers to INSERT statement not SELECT so there are no rows to return.

Upvotes: 1

Related Questions