我编写了一个函数,它使用表值参数将数据发送到 T-SQL 存储过程。这是我第一次这样做,我被这个错误卡住了:
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 a procedure to insert batch of objects
CREATE PROCEDURE Proc_InsertObjectBatch @InsertObjects_TVP ObjectTableType READONLY AS
-- Declare a variable holding return value
DECLARE @return_value integer;
-- Declare a table to hold oid of created objects
DECLARE @OutputTable TABLE (oid bigint);
-- Insert objects
INSERT INTO dbo.object_table(stkey, otkey, orev)
OUTPUT INSERTED.oid INTO @OutputTable
SELECT * from @InsertObjects_TVP;
-- Return oid's
SELECT oid FROM @OutputTable;
SET @return_value = 0;
RETURN @return_value
-- End of stored procedure Proc_InsertObjectBatch
这是表格类型。
-- Create ObjectTableType
CREATE TYPE ObjectTableType AS TABLE
(
stkey integer,
otkey integer,
orev bigint
)
任何帮助如何解决这个问题将不胜感激。