PDA

View Full Version : StoredProcedure doesn't return any rows on SQL Server 200


bjornwang
02-09-2007, 07:34 AM
Hello,

My team an I are facing some new problems with stored procedures that surfaced when switching form SQL Server 2005, in our test environment, to 2000 in the production environment.

On SQL Server 2000 no rows are returned when calling QueryByNamedParam(...). The stored procedure return rows as expected when called directly from SQL Management Studio:

exec sp_mp_get_col_contents
@page_id=1051, @col_num=1,
@flg_contents=0, @flg_clip=0,
@num_rows=10, @first_row=1,
@flg_preview=0, @preview_date=null,
@so_id=null, @date_format=104,
@flg_list_docs=1, @flg_list_imgs=0;


I'm initializing my StoredProcedure subclass using DeriveParameters(), and this does not throw any errors. I tried changing the parameters passed to QueryByNamedParam() to faulty values, and this throws an exception. To me, this indicates that the connection to the database is established, that the stored procedure is identified, and that the parameters it accepts are picked out correctly by Spring.

The result set from Spring, however, is always empty.

Using Debugging from Visual Studio, I can see that the MapRow(...) method in my RowMapper is never called. It seems no return rows are found by Spring, and then naturally no rows are mapped.

What I have noticed during my testing, is that Spring hides exceptions when parameters are assigned the wrong type, at least when using DeriveParameters() / QueryByNamedParam(...). For example, I can call an integer attribute of my stored procedure with a string value, and this passes without notice. ADO.NET usually throws exceptions for this, and I guess Spring somehow eats these. As the code works for us on SQL Server 2005, however, I guess this is all irrelevant.

I'm testing the situation from NUnit tests now, but I'm at a loss as to how I can configure the StoredProcedure class to do logging programatically, so I can get som more background information on the situation.

The code I'm using looks like this (convenience methods removed for clarity):

public class MogulPublishingNewsDAO : StoredProcedure, INewsDAO
{
private static readonly new ILog log = LogManager.GetLogger(typeof(MogulPublishingNewsDAO ));

private static string procedureName = "sp_mp_get_col_contents";


public NewsDAO(IDbProvider dbProvider, string baseUrl) : base(dbProvider, procedureName)
{
DeriveParameters();
AddRowMapper("articleRowMapper", new NewsFeedRowMapper(baseUrl));
Compile();
}


public virtual IList<NewsArticle> GetNews(int pageId, int colNum, int numRows)
{
IDictionary inParams = new Hashtable();
inParams["@page_id"] = pageId;
inParams["@col_num"] = colNum;
inParams["@flg_contents"] = 0; // Do not transfer document contents
inParams["@flg_clip"] = 0; // Do not clip document content (not transferred)
inParams["@num_rows"] = numRows;
inParams["@first_row"] = 1; // First row to transfer
inParams["@flg_preview"] = 0; // Do not preview documents under construction
inParams["@preview_date"] = null; // Preview date is irrelevant
inParams["@so_id"] = null; // Use standard sort order
inParams["@date_format"] = 104; // Use standard norwegian date format
inParams["@flg_list_docs"] = 1; // Include published documents;
inParams["@flg_list_imgs"] = 0; // Do not published images;

IDictionary outParams = QueryByNamedParam(inParams);
IList newsArticleList = outParams["articleRowMapper"] as IList;
return convertToTypedList(newsArticleList);
}


private static IList<NewsArticle> convertToTypedList(IList tmpList)
{
// TODO: The whole method should be removed when Spring supports generic
// row mappers for StoredProcedures using the AddRowMapper() method.
IList<NewsArticle> returnList = new List<NewsArticle>(tmpList.Count);
foreach (object o in tmpList)
{
returnList.Add(o as NewsArticle);
}
return returnList;
}


private class NewsFeedRowMapper : IRowMapper
{
private string baseUrl;

public NewsFeedRowMapper(string baseUrl)
{
this.baseUrl = baseUrl;
}

public object MapRow(IDataReader dataReader, int rowNum)
{
NewsArticle article = new NewsArticle();
article.Url = _buildUrlFromColumnElementId(dataReader.GetInt32(0 ));
article.Title = dataReader.GetString(2);
article.PublishDate = _convertToDate(dataReader.GetString(4));
return article;
}
}

}

Mark Pollack
02-12-2007, 01:15 AM
Hi,

I reproduced your situation as best I could (my unit test is in vs.net 2005 and hitting sqlserver 2000) but didn't run into the same problem. Can you post the variable types in your stored procedure declaration?

As for changing the log level programmatically, if you are using log4net then you can use that API directly but there isn't much logging into related to code pathway you are exercising. I'll look into the issue with assigning types that can be coorced into the right type, i.e. "1" (string)and 1 (int).

Cheers,
Mark

bjornwang
02-12-2007, 09:23 AM
Hello Mark,

Thank you very much for looking into this issue. It's very much appreciated.

This thread was forked from another discussion about the same Stored Procedure. You'll find the procedure definition there:
http://forum.springframework.net/showthread.php?t=1457

Note that the variable types might not be the problem, I mentioned them more as a sidenote. (Just so I don't lead you on a goose chase.) The real problem is the missing result set.

Meanwhile I'll try to put together a test which can hopefully reproduce the problems we have.

bjornwang
02-12-2007, 11:31 AM
Hello again Mark,

Attached, you'll find scripted versions of the Stored Procedure and tables from SQL Server 2000 created using the 2005 SQL Server Management Studio.

When I use this procedure for testing, it produces the error even on SQL Server 2005: No rows are returned from the procedure when running the code enclosed earlier. It seems at least that the database version is not the issue.

To use the procedure, run the script that creates the tables and the procedure first, then run the script that fills the tables with example data.

Try the procedure with the following SQL statement:

exec sp_mp_get_col_contents @page_id = 1051, @col_num = 1, @num_rows = 10;

This statement relies on default values for the procedure parameters as declared in the procedure definition, and should return 10 rows of data.

As Spring seems to need the full parameter list (doesn't handle default values), use the full parameter list specified earlier in this thread when calling the procedure from Spring.

lukeforehand
04-05-2007, 08:30 PM
The problem is most likely due to a bug with the version of sql server jdbc you are using.

http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=307890&SiteID=1

You will see that if you retrieve any output parameter before you retrieve the result set, the result set becomes empty due to a bug. This can be duplicated without the use of Spring templates.

Mark Pollack
04-06-2007, 12:51 PM
Hi,

Luke, this isn't a java app - you have the forums confused with the Spring.Java ones, but I appreciate the effort - it is good to know that info in anycase.

Bjorn, I've download the stored proc and will try it out. Sorry I didn't get to it before. I've had another similar report w.r.t. to stored procs. Also, I'll see what can be done w.r.t. to not having to specify those parameters that have default values but at the same time ensure that all required ones are provided before invoking the stored proc.

Cheers,
Mark

Mark Pollack
04-06-2007, 09:59 PM
Hi Bjorn,

I imported your schema and data into sqlserver 2000 database and was able to execute and get return values for the stored procedure from the subclass of Spring's StoredProcedure class. I am using .net 2.0. I'm attaching the code in case it helps, which is essentially what you posted.

Cheers,
Mark

bjornwang
04-09-2007, 06:26 PM
Hello,

Thanks for following up on this.

The good news is that with the latest nightly builds, the problem seems to have gone away.

We decided to go with straight ADO instead of Spring for the stored procedures some time back, so I can't put my finger on which exact build fixed the problem -- or if it was something else entirely.

I think we'll try using Spring instead now, as this is a much more elegant solution. Any developments yet on allowing Generic RowMappers? (see http://forum.springframework.net/showthread.php?t=1571.)

Mark Pollack
04-13-2007, 08:12 PM
Hi Bjørn,

No progress as of yet. I've changed the entry in JIRA so it appears on the task list for our next release.

Cheers,
Mark