0

Я написал функцию, которая отправляет данные в хранимую процедуру T-SQL с использованием табличных параметров. Ее первый раз, когда я сделал это, и я застрял на этой ошибке:SQL Исходный клиентский интерфейс ошибки 8058 при использовании параметра таблицы, не может диагностировать причину

The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. Table-valued parameter 1, to a parameterized string has no table type defined. 

К сожалению, я не могу найти какие-либо ресурсы в сети, которые дают решения, как исправить такую ​​ошибку. И из сообщения я остался без понимания, что здесь не так.

Ошибка возникает, когда SQLExecDirectA вызывается в коде ниже.

ErrorCode SQLif::InsertObjectBatch(ObjTypeKey* pObjectTypeKeys, ObjectId* pObjectIds, unsigned int numObjects) 
{ 
    ErrorCode ec = ACK; 
    EnterCriticalSection(m_pcs); 

    SQLRETURN ret; 
    SQLHSTMT hStmt; 

    StorageClass* pStorageClasses = new StorageClass[numObjects]; 
    RevisionId* pRevisionIds = new RevisionId[numObjects]; 

    if (!pStorageClasses || !pRevisionIds) 
    { 
     if (pStorageClasses) delete pStorageClasses; 
     if (pRevisionIds) delete pRevisionIds; 
     LeaveCriticalSection(m_pcs); 
     return NACK("SQLif::InsertObjectBack: Allocation failure allocating arrays"); 
    } 

    for (unsigned int i = 0; i < numObjects; i++) 
     pStorageClasses[i] = PERSIST; 
    for (unsigned int i = 0; i < numObjects; i++) 
     pRevisionIds[i] = 0; 


    // Variable for TVP row count; 
    SQLINTEGER cbTVP; 

    unsigned long long objectIdParam = 0; 
    SQLLEN objectIdParamLen = sizeof(objectIdParam); 

    // Allocate a statement handle 
    if ((ec = AllocStatementHandle(&hStmt)) != ACK) 
    { 
     LeaveCriticalSection(m_pcs); 
     return ec; 
    } 

    // Bind paramters for call 
    if (ec == ACK) 
    { 
     ret = SQLBindParameter(hStmt, // Statement handle 
           1,  // ParameterNumber 
           SQL_PARAM_INPUT, // InputOutputType 
           SQL_C_DEFAULT,  // ValueType 
           SQL_SS_TABLE,  // ParameterType 
           (SQLINTEGER) numObjects, // Number of rows in TVP 
           0,     // Number of columns in TVP 
           NULL,    // not needed 
           NULL,    // not needed 
           &cbTVP); 
     if ((ret != SQL_SUCCESS) && (ret != SQL_SUCCESS_WITH_INFO)) ec = NACK("SQLif::InsertObjectBatch: Binding to parameter 1 failed"); 
    } 

    // Bind colums for the TVP (param 1) 
    if (ec == ACK) 
    { 
     ret = SQLSetStmtAttr(hStmt, SQL_SOPT_SS_PARAM_FOCUS, (SQLPOINTER) 1, SQL_IS_INTEGER); 
     if ((ret != SQL_SUCCESS) && (ret != SQL_SUCCESS_WITH_INFO)) ec = NACK("SQLif::InsertObjectBatch: Setting Focus to TVP failed"); 
    } 

    // Bind column 1 
    if (ec == ACK) 
    { 
     ret = SQLBindParameter(hStmt, 1, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, pStorageClasses, sizeof(SQLINTEGER), NULL); 
     if ((ret != SQL_SUCCESS) && (ret != SQL_SUCCESS_WITH_INFO)) ec = NACK("SQLif::InsertObjectBach: Binding to column 1 of TVP failed"); 
    } 
    // Bind column 2 
    if (ec == ACK) 
    { 
     ret = SQLBindParameter(hStmt, 2, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, pObjectTypeKeys, sizeof(SQLUINTEGER), NULL); 
     if ((ret != SQL_SUCCESS) && (ret != SQL_SUCCESS_WITH_INFO)) ec = NACK("SQLif::InsertObjectBach: Binding to column 2 of TVP failed"); 
    } 
    // Bind column 3 
    if (ec == ACK) 
    { 
     ret = SQLBindParameter(hStmt, 3, SQL_PARAM_INPUT, SQL_C_UBIGINT, SQL_BIGINT, 0, 0, pRevisionIds, sizeof(SQLUBIGINT), NULL); 
     if ((ret != SQL_SUCCESS) && (ret != SQL_SUCCESS_WITH_INFO)) ec = NACK("SQLif::InsertObjectBach: Binding to column 3 of TVP failed"); 
    } 
    // Release focus 
    if (ec == ACK) 
    { 
     ret = SQLSetStmtAttr(hStmt, SQL_SOPT_SS_PARAM_FOCUS, (SQLPOINTER) 0, SQL_IS_INTEGER); 
     if ((ret != SQL_SUCCESS) && (ret != SQL_SUCCESS_WITH_INFO)) ec = NACK("SQLif::InsertObjectBatch: Resetting Focus failed"); 
    } 

    // Initialize row count 
    cbTVP = numObjects; 

    if (ec == ACK) 
    { 
     ret =SQLExecDirectA(hStmt, (SQLCHAR*)"EXEC Proc_InsertObjectBatch ?", SQL_NTS);  
     if ((ret != SQL_SUCCESS) && (ret != SQL_SUCCESS_WITH_INFO)) ec = GetErrorMessage(hStmt); 
    } 

    if (ec == ACK) 
    { 
     ret = SQLBindCol(hStmt, 1, SQL_C_UBIGINT, &objectIdParam, sizeof(objectIdParam), &objectIdParamLen); 
     if (ret != SQL_SUCCESS) ec = NACK("SQLif::InsertObjectBatch: Binding to column 1 failed"); 
    } 

    bool bHasData = false; 
    unsigned int i = 0; 
    if (ec == ACK) 
    { 
     while ((ret = SQLFetch(hStmt)) != SQL_NO_DATA) 
     { 
      if ((ret != SQL_SUCCESS) && (ret != SQL_SUCCESS_WITH_INFO)) ec = NACK("SQLif::RetrieveAttribute: Unable to fetch rows"); 

      bHasData = true; 
      pObjectIds[i] = objectIdParam; 
     } 
    } 
    FreeStatementHandle(hStmt); 

    LeaveCriticalSection(m_pcs); 

    return ACK; 
} 

Это соответствующая хранимая процедура.

Это тип таблицы.

-- Create ObjectTableType 
CREATE TYPE ObjectTableType AS TABLE 
(
    stkey integer, 
    otkey integer, 
    orev bigint 
) 

Любая помощь, как исправить это было бы весьма полезно.

ответ

0

Эта модификация сделала трюк.

SQLWCHAR* TVP = (SQLWCHAR*) L"ObjectTableType"; 
// Bind paramters for call 
if (ec == ACK) 
{ 
    ret = SQLBindParameter(hStmt, // Statement handle 
          1,  // ParameterNumber 
          SQL_PARAM_INPUT, // InputOutputType 
          SQL_C_DEFAULT,  // ValueType 
          SQL_SS_TABLE,  // ParameterType 
          (SQLINTEGER) numObjects, // Number of rows in TVP 
          0,     // Number of columns in TVP 
          TVP,    // Specify Table type 
          SQL_NTS,    // Termination method for table type 
          &cbTVP); 
    if ((ret != SQL_SUCCESS) && (ret != SQL_SUCCESS_WITH_INFO)) ec = NACK("SQLif::InsertObjectBatch: Binding to parameter 1 failed"); 
}