开发者

Sybase IN and OUT parameters

I'm going nuts about how the Sybase JDBC driver handles stored procedures with mixed IN and OUT parameters. Check out this simple stored procedure:

CREATE OR REPLACE PROCEDURE p (IN i1 INT, OUT o1 INT, IN i2 INT, OUT o2 INT)
BEGIN
    set o1 = i1;
    set o2 = i2;
END

And here's how I'd call it with JDBC:

CallableStatement c = connection.prepareCall("{ call dba.p(?, ?, ?, ?) }");
c.setInt(1, 1);
c.setInt(3, 2);
c.registerOutParameter(2, Types.INTEGER);
c.registerOutParameter(4, Types.INTEGER);
c.execute();
System.out.println(c.getObject(2));
System.out.println(c.getObject(4));

But this results in

1
null

What's 开发者_StackOverflow社区going on?? Is that a really wicked bug in the JDBC driver or am I completely missing something? By trial and error, I found this to be a way how it works:

c.setInt(1, 1);
c.setInt(2, 2);
c.registerOutParameter(3, Types.INTEGER);
c.registerOutParameter(4, Types.INTEGER);
c.execute();
System.out.println(c.getObject(3));
System.out.println(c.getObject(4));

Now the result is

1
2

Does the JDBC driver secretly re-order IN and OUT parameters??

I'm using SQL Anywhere 12 and jconn3.jar


Looks like a bug in the driver.

I suspect the buggy driver expects parameters to be passed/registered in the order (i.e. 1,2,3,4). When you do registerOut(2), the statement apparently forgets you did set(3) :-)

Or, may be, all OUT should be done after all IN. Then again, this is a bug in the driver.

UPDATE

Wait, you didn't change the procedure for the second variant? That result doesn't make any sense. Unless, as you said, driver does reordering. Which is unusual, to say the least.

UPDATE 2

I have decompiled the driver. It does some pretty funny games around out parameters, and with all this joggling I feel they have a fair potential for a bug there, but so far I do not see it plainly.

The only funny thing I noticed is that apparently if the parameter at position n is not out, the driver will scan parameters forward until it will find the value; if value is not found, it goes to the next row:

  s.registerOutParameter(5,Types.INT);
  ...
  // no out value at position 4, it will go to 5 and get the value
  rs.getInteger(4);

UPDATE 3

It may be interesting to see the output of all 4 parameters in example 1, i.e.:

CallableStatement c = connection.prepareCall("{ call dba.p(?, ?, ?, ?) }");
c.setInt(1, 1);
c.setInt(3, 2);
c.registerOutParameter(2, Types.INTEGER);
c.registerOutParameter(4, Types.INTEGER);
c.execute();
System.out.println(c.getObject(1));
System.out.println(c.getObject(2));
System.out.println(c.getObject(3));
System.out.println(c.getObject(4));


I tried this with Oracle 9.2 and it works as expected.. I think this problem is related to your JDBC driver, not to JDBC itself.

    public static void main(String[] args) throws Exception {

    Connection connection = getConnection();

    CallableStatement c = connection.prepareCall("{ call p(?, ?, ?, ?) }");
    c.setInt(1, 1);
    c.setInt(3, 2);
    c.registerOutParameter(2, Types.INTEGER);
    c.registerOutParameter(4, Types.INTEGER);
    c.execute();
    System.out.println(c.getObject(2));
    System.out.println(c.getObject(4));

}

Output:

Connected to database
1
2


Below sybase stored procedure works for me
public String IDGEN(String tableName,  Connection con , LOG _log)
    { 
        String strReturnValue = "-1"; 
        try
        {
             CallableStatement cs = con.prepareCall("{call usp_NEWPK_string_v6(?,?)}");
             cs.registerOutParameter(2,java.sql.Types.NUMERIC);
             cs.setString(1,tableName);
             cs.setInt(2,0);
             cs.execute();
             strReturnValue = cs.getLong(2) + "";

        } catch (Exception ex) {
            _log.logInstance(" ERROR: [IDGEN] " + ex.getMessage()); 
        }
        return strReturnValue;
    } 
// abobjects.com

create proc usp_NEWPK_string_v6 (@tablename  varchar(32) , @ID  numeric output
          )
as
declare @newValue     numeric
declare @oldValue  numeric
select @oldValue=IDGEN_ID from DB_IDGEN where IDGEN_TableName = @tablename
select @newValue=@oldValue + 1 from DB
 _IDGEN where IDGEN_TableName = @tablename
update DB_IDGEN set IDGEN_ID = @newValue where IDGEN_TableName = @tablename
select @ID  = @oldValue
return
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜