views:

4877

answers:

10

VB.net web system with a SQL Server 2005 backend. I've got a stored procedure that returns a varchar, and we're finally getting values that won't fit in a varchar(8000).

I've changed the return parameter to a varchar(max), but how do I tell the OleDbParameter.Size Property to accept any amount of text?

As a concrete example, the VB code that got the return parameter from the stored procedure used to look like:

objOutParam1 = objCommand.Parameters.Add("@RStr", OleDbType.varchar)
objOutParam1.Size = 8000
objOutParam1.Direction = ParameterDirection.Output

What can I make .Size to work with a (max)?

Update:

To answer some questions:

For all intents and purposes, this text all needs to come out as one chunk. (Changing that would take more structural work than I want to do - or am authorized for, really.)

If I don't set a size, I get an error reading "String[6]: the Size property has an invalid size of 0."

A: 

What does this large string look like? Is it perhaps something that could be better returned through an additional record set, or is it just note text?

Joel Coehoorn
+1  A: 

Have you tried not specifying the size?
Could you return a TEXT instead of a VARCHAR(MAX)?

jdecuyper
Not specifying a size throws a different error. Returning Text fails for a couple of reasons - it's deprecated, SQL2005 doesn't seem to want to cast between varchar and text - and it's against corp policy to use TEXTs.
Electrons_Ahoy
+7  A: 

Can you use ADO.NET?

Edit: To clarify, I am just suggesting that you might want to consider ADO.NET since you're working with VB.NET 2005 and SQL Server 2005--OLEDB was the pre-.NET way of accessing databases, so you may find more flexibility by using ADO.NET instead.

You shouldn't return VARCHARs from a stored procedure. I'm not even sure you can.

However, if you use an OUT parameter, you shouldn't have to specify it by size. For example:

SqlParameter p = new SqlParameter("@RStr", SqlDbType.VarChar);
p.Direction = ParameterDirection.Output;

Not sure whether this will suit your needs, but it should work just fine.

Ed Altorfer
OleDb only supports up to varchar(8000), so this is exactly the cause of the problem.
Joel Coehoorn
Joel--you definitely caught a limitation of OleDb that I didn't know about. Very good point.
Ed Altorfer
A: 

Have you tried specifying:

objOutParam1.Size = Int32.MaxValue;
James Curran
Yes. The varchar return type specified in the parameter constructor limits the return value to the first 8000 chars. There doesn't seem to be a varchar(max) return type. (?)
Electrons_Ahoy
+7  A: 

Upvoted Ed Altofer. (He answered first, so if you like my answer vote his too).

OleDb is your problem. It's a generic database connection that needs to talk to more than just SQL Server, and as a result you have a lowest common denominator situation where only the weakest composite feature set can be fully supported. One of the lost features is varchar(max) support.

You're using SQL Server 2005 and VB.Net. What's stopping your from using System.Data.SqlClient rather than System.Data.OleDb?

Edit
I found the documentation on the issue. See here:
http://msdn.microsoft.com/en-us/library/ms131035.aspx

The relevant portion:

Return values of data type varchar(max), nvarchar(max), varbinary(max), xml, udt, or other large object types can not be returned to client versions earlier than SQL Server 2005. If you wish to use these types as return values, you must use SQL Server Native Client.

Joel Coehoorn
Frankly - my boss. The whole system is built on top of the OleDB connection, and I have to live with it. Believe me, if I was architecting this, I'd be all over the better version. (Of course, if I was in charge, the sproc I was trying to fix wouldn't even exist...)
Electrons_Ahoy
A: 

The short answer is use TEXT instead of VARCHAR(max). 8K is the maximum size of a database page, where all your data columns should fit in except BLOB and TEXT. Meaning, your available capacity is less than 8k because of your other columns.

BLOB and TEXT is so Web 1.0. Bigger rows mean bigger database replication time, and bigger file I/O. I suggest you maintain a separate file server with an HTTP interface for that.

And, for the previous column

DataUrl VARCHAR(255) NOT NULL,

When inserting a new row, first compute the MD5 checksum of the data. Second, upload the data to the file server with the checksum as the filename. Third, INSERT INTO ...(...,DataUrl) VALUES(..., "http://fileserver/get?id=" . md5_checksum_data)

With this design, your database will stay calm even if the average data size becomes 1000x.

yogman
This is plain wrong. varchar(max) is stored outside of the row if the data is long enough.
erikkallen
Should also mention that the TEXT and IMAGE data types are deprecated. There is no such thing as a BLOB in SQL Server (it's called Image or varbinary(max)).
erikkallen
TEXT is deprecated in SQL Server 2005? I didn't know that. Can you share the source?
yogman
A: 

Just use int.MaxValue for the parameter size. The byte[] out of the sproc will be of the correct length. (I'm acutally using varbinary but the results will be the same).

 param.Size = int.MaxValue;
 param.SqlDbType = SqlDbType.VarBinary;
PaulB
A: 

Have you tried with "OleDbType.LongVarChar", this type maps to Text in SQL server 2K, and lets you retrieve more than 8K characters.

Pop Catalin
+3  A: 

I think using -1 for the size would work. At least it should with ADO.NET. Like this:

objOutParam1 = objCommand.Parameters.Add("@RStr", OleDbType.varchar, -1)

This is a long article, but it shows using -1 in the last example:

http://msdn.microsoft.com/en-us/library/bb399384.aspx

A: 

The -1 option works pretty well. I use it in several cases where I have a varchar(max) return from a stored proc.

Jamie Barrows