skip to Main Content

I have a function which calls a stored procedure with providing its parameters.

int8 CDBAgent::CreateKnights(uint16 sClanID, uint8 bNation, string & strKnightsName, string & strChief, uint8 bFlag)
{
    int8 bRet = -1;
    unique_ptr<OdbcCommand> dbCommand(m_GameDB->CreateCommand());
    if (dbCommand.get() == nullptr)
        return bRet;


    dbCommand->AddParameter(SQL_PARAM_OUTPUT, &bRet);
    dbCommand->AddParameter(SQL_PARAM_INPUT, strKnightsName.c_str(), strKnightsName.length());
    dbCommand->AddParameter(SQL_PARAM_INPUT, strChief.c_str(), strChief.length());

    if (!dbCommand->Execute(string_format(_T("{? = CALL CREATE_KNIGHTS ( %d, %d, %d, ?, ?)}"), sClanID, bNation, bFlag)))
        ReportSQLError(m_GameDB->GetError());


    return bRet;
}

and the stored procedure;

USE [KN_online]
GO
/****** Object:  StoredProcedure [dbo].[CREATE_KNIGHTS]    Script Date: 09/04/2016 03:09:46 ******/
SET ANSI_NULLS OFF
GO
SET QUOTED_IDENTIFIER ON
GO
-- Batch submitted through debugger: SQLQuery4.sql|7|0|C:UsersLethAppDataLocalTemp~vs3286.sql

/****** Object:  Stored Procedure dbo.CREATE_KNIGHTS    Script Date: 6/6/2006 6:03:32 PM ******/

-- modify by sungyong 2002.09.27

ALTER PROCEDURE [dbo].[CREATE_KNIGHTS]
@nRet       smallint OUTPUT,
@index      smallint,
@nation     tinyint,
@community  tinyint,
@strName    char(21), 
@strChief   char(21)


AS

DECLARE @Row tinyint, @knightsindex smallint, @knightsname char(21)
    SET @Row = 0    SET @knightsindex = 0  SET @knightsname = ''

    SELECT @Row = COUNT(*) FROM KNIGHTS WHERE IDNum = @index or  IDName = @strName

    IF @Row > 0 or @index = 0
    BEGIN
        SET @nRet =  3
        RETURN
    END

    --SELECT @Row = COUNT(*) FROM KNIGHTS WHERE IDName = @strName

    --IF @Row > 0
--  BEGIN
    --  SET @nRet =  3
        --RETURN
--  END

BEGIN TRAN  

    INSERT INTO KNIGHTS ( IDNum, Nation, Flag, IDName, Chief  ) 
    VALUES   (@index, @nation, @community, @strName, @strChief )

    INSERT INTO KNIGHTS_USER ( sIDNum, strUserID  ) 
    VALUES   (@index,  @strChief )

    IF @@ERROR <> 0
    BEGIN    
        ROLLBACK TRAN 
        SET @nRet =  6
        RETURN
    END

--  UPDATE USERDATA SET Knights = @index, Fame = 1 WHERE strUserId = @strChief  -- 1 == Chief Authority

    IF @@ERROR <> 0
    BEGIN    
        ROLLBACK TRAN 
        SET @nRet =  6
        RETURN
    END

COMMIT TRAN
SET @nRet =  0

The problem is when the stored procedure is called it passes the value of sClanID to bRet which is something I found by executing the statement directly on the SQL server (2008 R2) because when I directly executing like;

exec CREATE_KNIGHTS 15001, 2, 1, "OpenKO", 'test'

it tries to convert char (OpenKO) to tinyint, and if I give a number as strName instead of OpenKO, it says procedure expects a parameter to @strChief, which was not supplied.

I have other functions with the same structure and they are perfectly fine in the manner of taking parameters correctly and returning the output but why does it not ? and How can I solve this ?

If you like you can see the whole project on github

For SEO to this question, as I mentioned below, If I enter the sClanID as words, it gives the error “Error converting data type char to tinyint” and if I enter numbers, it gives “expects parameter @statement, which was not supplied”

2

Answers


  1. Chosen as BEST ANSWER

    Although I managed to solve my question, I won't accept my own answer since I'm looking an answer according to its cause.

    I solved it by just giving the first parameter as bRet to the ODBC command, so the last version of the code was;

    int8 CDBAgent::CreateKnights(uint16 sClanID, uint8 bNation, string & strKnightsName, string & strChief, uint8 bFlag)
    {
        int8 bRet = -1;
        unique_ptr<OdbcCommand> dbCommand(m_GameDB->CreateCommand());
        if (dbCommand.get() == nullptr)
            return bRet;
    
    
        dbCommand->AddParameter(SQL_PARAM_OUTPUT, &bRet);
        dbCommand->AddParameter(SQL_PARAM_INPUT, strKnightsName.c_str(), strKnightsName.length());
        dbCommand->AddParameter(SQL_PARAM_INPUT, strChief.c_str(), strChief.length());
    
        if (!dbCommand->Execute(string_format(_T("{? = CALL CREATE_KNIGHTS (%d, %d, %d, %d, ?, ?)}"), bRet, sClanID, bNation, bFlag)))
            ReportSQLError(m_GameDB->GetError());
    
    
        return bRet;
    }
    

    Since, the problem caused because there was a parameter shift while passing the values to the SP, just passing a initial value the OUTPUT variable solved the problem.


  2. The best practice is putting OUTPUT parameters declaration always at the end, and call SP with parameter names.

    ALTER PROCEDURE [dbo].[CREATE_KNIGHTS]
    @index      smallint,
    @nation     tinyint,
    @community  tinyint,
    @strName    char(21), 
    @strChief   char(21),
    @nRet       smallint OUTPUT
    

    The following statement should change like that;

    if (!dbCommand->Execute(string_format(_T("{CALL CREATE_KNIGHTS ( %d, %d, %d, ?, ?, ?)}"), sClanID, bNation, bFlag)))
    

    And the code should be like this;

        dbCommand->AddParameter(SQL_PARAM_INPUT, strKnightsName.c_str(), strKnightsName.length());
        dbCommand->AddParameter(SQL_PARAM_INPUT, strChief.c_str(), strChief.length());
        dbCommand->AddParameter(SQL_PARAM_OUTPUT, &bRet);
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search