views:

563

answers:

2

I have a Firebird stored procedure that accepts Decimal(9,6) values for Latitude and Longitude parameters. It's used to create a contact profile for a user.

When I try to create and use these decimal parameters, I get a conversion error:

Value was too large or too small for an Int32.

Here's how I create the ADO.Net connection:

FbConnection dbConn = new FbConnection(ConnectionString);

And further on, here's where I set up the command:

        IDbCommand command = _Connection.CreateCommand();
        command.Connection = _Connection;
        command.CommandText = "CREATECONTACT";
        command.CommandType = CommandType.StoredProcedure;

The code I'm using to create the ADO.Net parameters looks like this:

IDataParameter param21 = command.CreateParameter();
param21.ParameterName = "GEOLAT";
param21.DbType = DbType.Decimal;
param21.Value = 3.14m;

After all the parameters are added I call command.ExecuteScalar() to get the value of the ContactId that was (hopefully) just created.

int contactId = Convert.ToInt32(command.ExecuteScalar(), CultureInfo.InvariantCulture);

It isn't the Convert.ToInt32 that causes the problem. The exception is thrown from ExecuteScalar(). I get the same error if the command looks like this:

object result = command.ExecuteScalar();

The procedure works fine if the values for GeoLat and GeoLong are integer values (such as 72 or 0), but if I try to pass a decimal value, it fails. For example:

IDataParameter param21 = command.CreateParameter();
param21.ParameterName = "GEOLAT";
param21.DbType = DbType.Int32;
param21.Value = 12;

Am I doing something wrong here?

I'm using the Firebird .NET data provider 2.5.1 against a Firebird 2.1.3 database.

UPDATE: At @bluecoder's request, I tried to build the .NET data provider from the source code. But I get a compile error at line 731 of GdsStatement.cs.

int processedItems = (rowDescs[part] != null ? rowDescs[part].Count : 0);

The error is:

There exist both implicit conversions from "short" to "int" and from "int" to "short".

Changing line 731 to this:

int processedItems = (rowDescs[part] != null ? (int) rowDescs[part].Count : 0);

Allows the code to compile on my machine.

After making this code change, I was able to run my tests and use decimals in my stored procedure successfully.

It appears that the trigger for the error is that I return the number of rows affected by my update statement as part of the procedure.

UPDATE2: Here's the full source for the SQL stored procedure. It's used to create an hCard record in my database.

SET TERM ^ ;
RECREATE PROCEDURE CREATECONTACT (
 TEMPLATECODE     SMALLINT,
 CREATEUSERID     INTEGER,
 CREATEDATE       TIMESTAMP,
 SECURITYCODE     SMALLINT,
 LINKTEXT         VARCHAR(255),
 GUID             VARCHAR(200),
 GIVENNAME        VARCHAR(200),
 FAMILYNAME       VARCHAR(200),
 ADDITIONALNAME   VARCHAR(200),
 HONORIFICPREFIX  VARCHAR(200),
 HONORIFICSUFFIX  VARCHAR(200),
 NICKNAME         VARCHAR(200),
 PHOTOLOCALFILEID INTEGER,
 LOGOLOCALFILEID  INTEGER,
 BIRTHDAY         TIMESTAMP,
 JOBTITLE         VARCHAR(200),
 "ROLE"           VARCHAR(200),
 ORGANIZATION     VARCHAR(255),
 NOTE             BLOB SUB_TYPE TEXT,
 GEOLAT           DECIMAL(9,6),
 GEOLONG          DECIMAL(9,6))
RETURNS (
 ENTITYID         INTEGER)
AS 
BEGIN
EXECUTE PROCEDURE CreateEntity :TEMPLATECODE, :CREATEUSERID, :CREATEDATE, :SECURITYCODE, :LinkText 
    RETURNING_VALUES EntityId;

INSERT INTO CONTACT (EntityId, GUID, GIVENNAME, FAMILYNAME, ADDITIONALNAME, 
HONORIFICPREFIX, HONORIFICSUFFIX, NICKNAME, PHOTOLOCALFILEID, LOGOLOCALFILEID, 
BIRTHDAY, JOBTITLE, "ROLE", ORGANIZATION, NOTE, GEOLAT, GEOLONG)
VALUES (:EntityId, :GUID, :GIVENNAME, :FAMILYNAME, :ADDITIONALNAME, 
:HONORIFICPREFIX, :HONORIFICSUFFIX, :NICKNAME, :PHOTOLOCALFILEID, 
:LOGOLOCALFILEID, :BIRTHDAY, :JOBTITLE, :ROLE, :ORGANIZATION, :NOTE, 
:GEOLAT, :GEOLONG);
SUSPEND;
END^
SET TERM ; ^

UPDATE3: I just tried this with the new Firebird Client 2.5.2 release and it's still having a problem. I think this is a bug. I'm going to report it on the Firebird Tracker.

UPDATE4: Oops. I discovered I had a stale reference to Firebird Client 2.5.1 in my GAC. Firebird Client 2.5.2 does fix the problem.

+2  A: 

Checking the obvious first:

1) Are you sure none of your Parameter.DbType are set to DbType.Int32?

2) Can you post the actual code where your debugger is encountering the error? (I'm assuming that is pseudocode above)

3) Did you verify that failure is at the Parameter.Value assignment line? (Not at the command execution, for example)


Source
Download .Net Provider Source - Provider
7zip to extract source (If you don't have it) - 7Zip

Build
[Backup your current source being modifying anything]
1) Right-click on your C# solution and select Add->Existing solution
2) select the *.csproj from the directory you extracted the Provider source to
[..\NETProvider\source\FirebirdSql\Data\FirebirdSql.Data.FirebirdClient.csproj]
3) Right-click on the FirebirdClient project and build it
4) Change the FirebirdSql.Data.FirebirdClient reference in your app to the version you just compiled
[..\Data\bin\Debug\FirebirdSql.Data.FirebirdClient.dll]

Now you should be able to step into (F11) your ExecuteScalar statement and see where the conversion exception is being raised.

Let me know if any of that doesn't made sense. I'm interested to see what you find

bluecoder
I'm sure that the parameters are set to DbType.Decimal in all cases. The exception occurs during command execution, not parameter assignment. I'll paste the line where it occurs into my question.
dthrasher
1)Is the ExecuteScalar returning a number that is too big for Int32 to handle? (>2,147,483,647) 2)Does the sql statement/procedure/table you are executing against have the correct data types? (In the database, are the datatypes not compatible)
bluecoder
1) Nope, the Ids of my contact table are in the hundreds. I'm not approaching the Int32 limit of the return value. 2) Both the stored procedure and table have the correct types. The procedure executes fine in the Firebird Maestro IDE.
dthrasher
Sorry for all the questions, continuing on:1) Have you tried running the ExecuteScalar without the Convert.ToInt32? For example, just try ExecuteScalar().ToString (Just want to rule out that object->Int32 conversion__ 2) Your code snippet doesn't have the declaration but can I assume that "command" is a FbCommand? I looked at the 2.5.1 code and don't see anywhere that a decimal to Int32 conversion would take place__3)When you say (72) or (0) work, are you setting those paramXX.Value? Are you setting paramXX.DbType = DbType.Int32?
bluecoder
No worries, @bluecoder. Thanks for taking the time to help me with this! I added more detail to my question in response to the questions you asked. I think I've eliminated everything but the Firebird Provider itself.
dthrasher
Well I set up a firebird/IBExpert environment and tried to reproduce the error but no luck. I tried both direct statements and stored procedures with ~30 parameters. I tried changing dbtype, procedure, and table definitions from decimal to integer but it truncated rather than throwing a conversion error. At this point I would suggest you download the .Net provider source so you can see deeper into what is throwing the error. I'll put a link/instructions above in my answer. Let me know if I can help any more.
bluecoder
I built the .NET provider according to your instructions. See the update in the original question. It looks like the problem has to do with the return value from my stored procedure. I return the number of rows affected by the update as part of my procedure.
dthrasher
Can you post the statement you are using to "return the number of rows affected" (SQL)? What is the definition (Name, Type, etc) of your procedure's return parameter?
bluecoder
The return parameter is an Integer type. I've pasted the full text of the stored proc into the question. (It'd be nice if StackOverflow allowed attachments.) I've used similar code in several other business entities, and this stored proc worked fine until I started working with GeoLat and GeoLong.
dthrasher
Hey @bluecoder, I discovered that Firebird .NET Provider 2.5.2 works with my test code. Thanks again for all your help!
dthrasher
A: 

I just discovered that I had a stale reference to Firebird Client 2.5.1 in my GAC. After removing this reference, I was able to run my test cases successfully.

The .NET Provider for Firebird version 2.5.2 does not have the problem I described in my question. The solution is to upgrade to the latest version of the .NET Provider for Firebird.

dthrasher
I'm glad you finally got it working :)
bluecoder