Выходные параметры не заполняют MSSQL ODBC - PullRequest
0 голосов
/ 18 февраля 2012

У меня проблемы с получением этого кода для заполнения выходных параметров клиентским драйвером MSSQL ODBC 10.0 и 9.0.Я могу подтвердить, что мое направление привязки установлено правильно.

Я также вызываю SQLMoreResults, моя хранимая процедура имеет установленный NOCOUNT и отлично работает в другой библиотеке на основе ODBC.В моем операторе execute он успешно выполняется, но SQLMoreResults всегда говорит, что результатов больше нет, и я понимаю, что эти параметры не заполняются, пока не пройдут все наборы результатов.Один выходной параметр, который я использую - это bigint.

К сожалению, я не знаю всех тонкостей разработки ODBC, и должно быть что-то важное, что я упускаю.Я пытаюсь повторно использовать мой дескриптор оператора, но я сбрасываю его после первого вызова SQLProcedureColumns и удаляю связанные переменные.Затем я перепривязываю.

Есть идеи, где я сбился с пути?

bool ODBCConnection::Execute()
{
    LLOG("Execute " << (void *)this << " " << (void *)session);
    if(session->hstmt == SQL_NULL_HANDLE)
        return false;
    if(IsCurrent())
        session->current = NULL;
    session->FlushConnections();
    last_insert_table.Clear();
    number.Clear();
    text.Clear();
    time.Clear();
    CParser p(statement);

    /* parse for stored procedure */

    bool isStoredProcedure = false;

    if (p.Char('{'))
    {
        p.Spaces();

          String procedure_name;

          p.Id("?");
          p.Id("=");

        if (p.Id("call") || p.Id("CALL")) {
            procedure_name = p.ReadId();
            isStoredProcedure = true;
            //Cout() << "Proc name: " << procedure_name << "\n";
        }

        SQLSetEnvAttr(session->henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_INTEGER);

        SDWORD      cbValue5;
        SDWORD      cbValue4;
        SQLSMALLINT ParameterType = SQL_PARAM_INPUT;

        if (!IsOk(SQLProcedureColumns (
                      session->hstmt,
                      NULL,
                      0,
                      NULL,
                      0,
                      (SQLCHAR *)~procedure_name,
                      procedure_name.GetLength(),
                      NULL,
                      0
                  ))) {
            SQLFreeStmt(session->hstmt, SQL_CLOSE);
            return false;
        }

        char parameter_name [20];

        if (!IsOk(SQLBindCol(
                      session->hstmt,
                      4, // Column 4 returns column name
                      SQL_C_CHAR,
                      parameter_name,
                      sizeof(parameter_name),
                      &cbValue4
                  ))) {
        }

        if (!IsOk(SQLBindCol(
                      session->hstmt,
                      5, // Column 5 returns whether parameter is input or output
                      SQL_C_SHORT,
                      &ParameterType,
                      0,
                      &cbValue5
                  ))) {
        }

        int i = 0;
        while (SQLFetch(session->hstmt) == SQL_SUCCESS) {
            Param& p = param[i];

            Cout() << ParameterType << "\n";    

            /*switch (ParameterType) {
                case SQL_PARAM_INPUT:
                case SQL_PARAM_OUTPUT:
                case SQL_PARAM_INPUT_OUTPUT:
                    p.direction = ParameterType;
                    break;

                case 5:
                    p.direction = SQL_PARAM_OUTPUT;
                    break;
                default:
                    break;
            }*/

            if(ParameterType == 5)
                p.direction = SQL_PARAM_OUTPUT;
            else
                p.direction = ParameterType;

            i++;
        }

        SQLFreeStmt(session->hstmt, SQL_CLOSE);
        SQLFreeStmt(session->hstmt, SQL_RESET_PARAMS);
        SQLFreeStmt(session->hstmt, SQL_UNBIND);
    }

    if((p.Id("insert") || p.Id("INSERT")) && (p.Id("into") || p.Id("INTO")) && p.IsId())
        last_insert_table = p.ReadId();

    if(!IsOk(SQLPrepare(session->hstmt, (SQLCHAR *)~statement, statement.GetCount())))
            return false;

    parse = false;
    bparam = param;
    param.Clear();

    for(int i = 0; i < bparam.GetCount(); i++) {
        Param& p = bparam[i];
        SQLSMALLINT     DataType;
        SQLULEN         ParameterSize;
        SQLSMALLINT     DecimalDigits;
        SQLSMALLINT     Nullable;

        Cout() << "Direction: " << p.direction << "\n";
        Cout() << "Length: " << p.li << "\n";

        if(!IsOk(SQLDescribeParam(session->hstmt, i + 1, &DataType, &ParameterSize, &DecimalDigits, &Nullable)))
            return false;
        if(!IsOk(SQLBindParameter(session->hstmt, i + 1, p.direction, p.ctype, DataType,
                                  ParameterSize, DecimalDigits, (SQLPOINTER)~p.data, p.data.GetLength(),
                                  &p.li)))
            return false;
    }
    SQLSMALLINT ncol;


    if(!isStoredProcedure)
    {

        if(!IsOk(SQLExecute(session->hstmt)) || !IsOk(SQLNumResultCols(session->hstmt, &ncol))) {
            Cout() << "SQLExecute crashed\n";
            SQLFreeStmt(session->hstmt, SQL_CLOSE);
            return false;
        }
    }
    else
    {
        Cout() << "statement: " << statement << "\n";

        if(!IsOk(SQLExecute(session->hstmt))) {
            Cout() << "SQLExecute crashed\n";
            SQLFreeStmt(session->hstmt, SQL_CLOSE);
            return false;
        }

        Cout() << "Calling SQLMoreResults...\n";

        //SQLFreeStmt(session->hstmt, SQL_CLOSE);
        int iReturn = SQLMoreResults(session->hstmt); 

        Cout() << "SQLMoreResults return code: " << iReturn << "\n";

        while (iReturn == SQL_SUCCESS || iReturn == SQL_SUCCESS_WITH_INFO) 
        { 
            iReturn = SQLMoreResults(session->hstmt); 
        } ;
        //SQLFreeStmt(session->hstmt, SQL_RESET_PARAMS);
        //SQLFreeStmt(session->hstmt, SQL_UNBIND);
        ncol = 0;
    }

    session->current = this;
    info.Clear();
    binary.Clear();
    for(int i = 1; i <= ncol; i++) {
        SQLCHAR      ColumnName[256];
        SQLSMALLINT  NameLength;
        SQLSMALLINT  DataType;
        SQLULEN      ColumnSize;
        SQLSMALLINT  DecimalDigits;
        SQLSMALLINT  Nullable;
        if(!IsOk(SQLDescribeCol(session->hstmt, i, ColumnName, 255, &NameLength, &DataType,
                                &ColumnSize, &DecimalDigits, &Nullable)))
            return false;
        binary.Add(false);
        SqlColumnInfo& f = info.Add();
        f.nullable = Nullable != SQL_NO_NULLS;
        f.binary = false;
        f.precision = DecimalDigits;
        f.scale = 0;
        f.width = ColumnSize;
        f.name = (char *)ColumnName;
        switch(DataType) {
        case SQL_DECIMAL:
        case SQL_NUMERIC:
        case SQL_SMALLINT:
        case SQL_INTEGER:
        case SQL_REAL:
        case SQL_FLOAT:
        case SQL_DOUBLE:
        case SQL_BIT:
        case SQL_TINYINT:
            f.type = DOUBLE_V;
            break;
        case SQL_BIGINT:
            f.type = INT64_V;
            break;
        case SQL_TYPE_DATE:
        case SQL_TYPE_TIMESTAMP:
            f.type = TIME_V;
            break;
        case SQL_BINARY:
        case SQL_VARBINARY:
        case SQL_LONGVARBINARY:
            f.type = STRING_V;
            f.binary = true;
            binary.Top() = true;
            break;
        default:
            f.type = STRING_V;
            break;
        }
    }
    SQLLEN rc;
    SQLRowCount(session->hstmt, &rc);
    rowsprocessed = rc;


    return true;
}

Ответы [ 2 ]

0 голосов
/ 21 февраля 2012

Неважно, я был глупым.Моя привязка параметров была фактически привязана к копии данных, а не к самим данным.Спасибо всем, кто пытался помочь.

0 голосов
/ 18 февраля 2012

Вы пытались включить SQLProfile?Возможно, запустите его и посмотрите, как настоящий SQL попадает в базу данных, затем возьмите эти операторы SQL и запустите их непосредственно в SSMS, чтобы убедиться, что он выполняет то, что вы ожидаете.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...