Wysyłanie danych jako parametr Valued tabela przy użyciu danych na wykonanie (ODBC)
Przypomina on Wszystko w pamięci procedura, ale używa danych na wykonanie parametru wartości w tabela.
W tym przykładzie gdy SQLExecute lub SQLExecDirect jest wywoływana, sterownik zwraca SQL_NEED_DATA. Następnie aplikacja wywołuje SQLParamData wielokrotnie, dopóki sterownik zwraca wartość inną niż SQL_NEED_DATA. Sterownik zwraca ParameterValuePtr informowanie aplikacji parametr, który żąda danych. Wywołania aplikacji SQLPutData Parametr danych przed następne wywołanie SQLParamData. Dla parametru wartości w tabela, wywołanie SQLPutData oznacza liczbę wierszy, które zostały przygotowane dla sterownika (w tym przykładzie zawsze 1). Gdy wszystkie wiersze z wartością tabela zostały przekazane do sterownika, SQLPutData nazywa się oznacza, że dostępne są 0 wierszy.
Istnieje możliwość użyć wartości danych na wykonywanie w wierszach wartość tabela.Wartość zwracana przez SQLParamData informuje o aplikacji, która wartość wymaga sterownika. Jako wartości parametru regularnych SQLPutData może zostać wywołana jeden lub więcej razy znaków lub binarne wartość kolumna wartości z tabela. Dzięki temu aplikacja do przekazania duże wartości w kawałkach.
When SQLPutData is called for a table-value, DataPtr is used for the number of rows available (in this example, always 1).StrLen_or_IndPtr must always be 0.Wartość tabela wszystkie wiersze zostały przekazane, SQLPutData jest wywoływana z DataPtr wartość 0.
Wymagania wstępne
W tej procedurze zakłada się, że następujące Transact-SQL zostało wykonane na serwerze:
create type TVParam as table(ProdCode integer, Qty integer)
create procedure TVPOrderEntry(@CustCode varchar(5), @Items TVPParam,
@OrdNo integer output, @OrdDate datetime output)
as
set @OrdDate = GETDATE();
insert into TVPOrd (OrdDate, CustCode) values (@OrdDate, @CustCode) output OrdNo);
select @OrdNo = SCOPE_IDENTITY();
insert into TVPItem (OrdNo, ProdCode, Qty)
select @OrdNo, @Items.ProdCode, @Items.Qty
from @Items
Aby przesłać dane
Deklarować zmienne dla parametrów SQL.Bufory dla wartości w tabela parametrów nie mają do tablic, w tym przykładzie, w przykładzie przechodzi jeden wiersz w czas.
SQLRETURN r; // Variables for SQL parameters: SQLCHAR CustCode[6]; SQLCHAR *TVP = (SQLCHAR *) "TVPInParam"; SQLINTEGER ProdCode, Qty; SQLINTEGER OrdNo; char *OrdDate[23]; SQLCHAR *TVP = (SQLCHAR *) "TVParam"; SQLINTEGER ItemNo; // Variables for indicator/length variables associated with parameters: SQLLEN cbCustCode, cbTVP, cbProdCode, cbQty, cbOrdNo, cbOrdDate, cbItemNo; // Token returned by SQLParamData to indicate which param data is needed for: SQLPOINTER ParamId;Bind the parameters.ColumnSize is 1, meaning that at most one row is passed at a time.
// Bind parameters for call to TVPOrderEntryByRow. r = SQLBindParameter(hstmt, 1, SQL_C_CHAR, SQL_PARAM_INPUT,SQL_VARCHAR, 5, 0, CustCode, sizeof(CustCode), &cbCustCode); // 2 - Items TVP r = SQLBindParameter(hstmt, 2, // ParameterNumber SQL_C_DEFAULT, // InputOutputType SQL_PARAM_INPUT, // ValueType SQL_SS_TABLE, // Parametertype 1, // ColumnSize: For a table-valued parameter this the row array size. 0, // DecimalDigits: For a table-valued parameter this is always 0. TVP, // ParameterValuePtr: For a table-valued parameter this is the type name of the TVP, // and also a token returned by SQLParamData. SQL_NTS, // BufferLength: For a table-valued parameter this is the length of the type name or SQL_NTS. &cbTVP); // StrLen_or_IndPtr: For a table-valued parameter this is the number of rows input and output. // 3 - OrdNo output r = SQLBindParameter(hstmt, 3, SQL_PARAM_OUTPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, &OrdNo, sizeof(SQLINTEGER), &cbOrdNo); // 4- OrdDate output r = SQLBindParameter(hstmt, 4, SQL_PARAM_OUTPUT, SQL_C_CHAR, SQL_TYPE_TIMESTAMP, 23, 3, &OrdDate, sizeof(OrdDate), &cbOrdDate);Wiązanie kolumny dla parametru wartości w tabela.
// Bind the table-valued parameter columns. // First set focus on param 2 r = SQLSetStmtAttr(hstmt, SQL_SOPT_SS_PARAM_FOCUS, (SQLPOINTER) 2, SQL_IS_INTEGER); // ProdCode r = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, &ProdCode, sizeof(SQLINTEGER), &cbProdCode); // Qty r = SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, &Qty, sizeof(SQLINTEGER), &cbQty); // Reset param focus r = SQLSetStmtAttr(hstmt, SQL_SOPT_SS_PARAM_FOCUS, (SQLPOINTER) 0, SQL_IS_INTEGER);Inicjowanie parametrów.W tym przykładzie ustawia rozmiar parametru wartości tabela SQL_DATA_AT_EXEC, a nie liczba wierszy.
// Initialze the TVP for row streaming. cbTVP = SQL_DATA_AT_EXEC; // Populate non-data-at-exec parameters. strcpy_s((char *) CustCode ,sizeof(CustCode), "CUST1"); cbCustCode = SQL_NTS;Call the procedure.SQLExecDirect will return SQL_NEED_DATA because the table-valued parameter is a data-at-execution parameter.
// Call the procedure r = SQLExecDirect(hstmt, (SQLCHAR *) "{call TVPOrderEntry(?, ?, ?, ?)}",SQL_NTS);Służy do dostarczania danych parametru danych na wykonanie.Kiedy SQLParamData Zwraca ParameterValuePtr w przypadku parametru wartości tabela aplikacji należy przygotować kolumny do następnego wiersza lub wierszy wartość tabela. Następnie wywołania aplikacji SQLPutData z DataPtr Ustaw liczbę wierszy, które są dostępne (w tym przykładzie 1) i StrLen_or_IndPtr należy ustawić na 0.
// Check if parameter data is required, and get the first parameter ID token if (r == SQL_NEED_DATA) { r = SQLParamData(hstmt, &ParamId); } // Supply parameter row data. int rowNum = 0; while (r == SQL_NEED_DATA) { if (ParamId == TVP) { switch (rowNum) { case 0: // Supply data for 1st row // Populate input table-valued parameter row constituent columns. ProdCode = 1215; cbProdCode = sizeof(SQLINTEGER); Qty = 5; cbQty = sizeof(SQLINTEGER); // Returning 1 for StrLenOrIndPtr indicates that a row is available. r = SQLPutData(hstmt, (SQLPOINTER) 1, 1); rowNum++; break; case 1: // Supply data for the second row. // Populate another table-valued parameter row as above. ProdCode = 1017; cbProdCode = sizeof(SQLINTEGER); // This time supply Qty through SQLPutData. Qty = 0; cbQty = SQL_DATA_AT_EXEC; r = SQLPutData(hstmt, (SQLPOINTER) 1, 1); rowNum++; break; default: // Passing 0 in StrLenOrIndPtr indicates that no more table-valued parameter rows are available. r = SQLPutData(hstmt, (SQLPOINTER) 1, 0); break; } } else { if (ParamId == &Qty) { Qty = 2; // For a character or binary parameter, SQLPutData could be called // multiple times to pass the value in pieces. SQLPutData(hstmt, &Qty, sizeof(SQLINTEGER)); } } // Signal that parameter data is available, and get the token for // the next parameter. r = SQLParamData(hstmt, &ParamId); } }
Przykład
Description
W przykładzie pokazano, którego można użyć wiersza przesyłania strumieniowego jeden wiersz na wywołanie SQLPutData, z TVP ODBC, podobnie jak BCP.exe można użyć do załadowania danych do bazy danych.
Przed budynku próbki, należy zmienić nazwa serwera w ciąg połączenia.
Będziesz potrzebować r. SQL Server 2008 Aktualizacja, aby uruchomić ten przykład. Jeśli nie jesteś w stanie wykonać w tym przykładzie, być może nie masz najnowszych aktualizacji, aktualizacji potrzebnych do uruchomienia w tym przykładzie znajduje się na Pakiet aktualizacji 2 dla programu SQL Server 2008.Wybierz plik o nazwie SQL_Server_2008_RTM_CU2_SNAC.
W przykładzie użyto domyślna baza danych.Przed uruchomieniem w tym przykładzie, uruchom następujące polecenia w bazie danych, który będzie używany:
create table MCLOG (
biSeqNo bigint,
iSeries int,
bmRestData varbinary(max)
)
go
-- Table type definition
create type MCLOGType
as table(biSeqNo bigint, iSeries int, bmRestData varbinary(max) )
go
-- Insert procedure
create procedure MCLOGInsert (@TableVariable MCLOGType READONLY)
as
insert into MCLog(biSeqNo, iSeries, bmRestData)
select biSeqNo, iSeries, bmRestData from @TableVariable
go
Code
#define UNICODE
#define _UNICODE
#define _SQLNCLI_ODBC_
#include <windows.h>
#include <tchar.h>
#include <sqlext.h>
#include "sqlncli.h"
// link to sqlncli10.lib
#define SUCCESS(x) ( \
!((x) & 0xFFFE) \
)
#define CHKRC(stmt) { \
rc = (stmt); \
if (!SUCCESS(rc)) { \
_tprintf(_T(#stmt) _T(" failed with rc = %ld\r\n"), rc); \
goto EXIT; \
} \
};
void PrintError(SQLSMALLINT HandleType, SQLHANDLE Handle) {
RETCODE rc = SQL_SUCCESS;
SQLTCHAR szSqlState[6];
SQLTCHAR szMessage[1024];
SQLSMALLINT i = 1;
SQLSMALLINT msgLen = 0;
SQLINTEGER NativeError;
i = 1;
while ( (rc = SQLGetDiagRec(HandleType, Handle, i, szSqlState, &NativeError, szMessage, sizeof(szMessage)/sizeof(SQLTCHAR), &msgLen)) != SQL_NO_DATA) {
if (!SUCCESS(rc))
break;
szMessage[msgLen] = 0;
szSqlState[5] = 0;
_tprintf(_T("SQLState=%s, NativeError=%ld, Message=%s\r\n"), szSqlState, NativeError, szMessage);
i++;
}
}
int main() {
RETCODE rc = SQL_SUCCESS;
HENV henv = SQL_NULL_HENV;
HDBC hdbc = SQL_NULL_HDBC;
SQLHSTMT hstmt = SQL_NULL_HSTMT;
SQLTCHAR * pszConnection = _T("DRIVER={SQL Server Native Client 10.0};Server=your_servername;Trusted_Connection=Yes;");
// insert one TVP parameter
SQLTCHAR * pszInsertStmt = _T("{call MCLOGInsert(?)}");
SQLLEN cbParamLength;
SQLULEN cMaxRows = 3;
CHKRC(SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HENV, &henv));
CHKRC(SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0));
CHKRC(SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc));
CHKRC(SQLSetConnectAttr(hdbc, SQL_ATTR_LOGIN_TIMEOUT,reinterpret_cast<SQLPOINTER>(60),SQL_IS_UINTEGER));
CHKRC(SQLDriverConnect(hdbc, NULL, pszConnection, SQL_NTS, NULL, 0, NULL, SQL_DRIVER_NOPROMPT));
CHKRC(SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt));
CHKRC(SQLPrepare(hstmt, pszInsertStmt, SQL_NTS));
// Bind the first parameter
CHKRC(SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_DEFAULT, SQL_SS_TABLE, cMaxRows, 0, (SQLPOINTER)1, 0, &cbParamLength));
// If the stored procedure is executed as T-SQL ("exec sp_insert ?, ?"), you will supply the type name.
// CHKRC(SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_DEFAULT, SQL_SS_TABLE, cMaxRows, 0, (SQLPOINTER)lpszTVPParamType, SQL_NTS, &cbParamLengths));
// bind TVP columns
CHKRC(SQLSetStmtAttr(hstmt, SQL_SOPT_SS_PARAM_FOCUS, (SQLPOINTER)1, SQL_IS_INTEGER));
// for each TVP column, you can define an array to send more than one row for each SQLPutData call.
LONGLONG llSeqNo;
SQLLEN cbSeqNo = sizeof(LONGLONG);
LONG lSeries;
SQLLEN cbSeries = sizeof(LONG);
BYTE rgbRestData[2048];
SQLLEN cbRestData = SQL_DATA_AT_EXEC;
SQLUSMALLINT iColumn = 1;
// Bind biSeqNo
CHKRC(SQLBindParameter(hstmt, iColumn, SQL_PARAM_INPUT, SQL_C_SBIGINT, SQL_BIGINT, sizeof(LONGLONG), 0, (SQLPOINTER)&llSeqNo, sizeof(llSeqNo), &cbSeqNo));
// Bind iSeries
iColumn++;
CHKRC(SQLBindParameter(hstmt, iColumn, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, sizeof(LONG), 0, (SQLPOINTER)&lSeries, sizeof(lSeries), &cbSeries));
// Bind bmRestData
iColumn++;
CHKRC(SQLBindParameter(hstmt, iColumn, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_VARBINARY, 0, 0, (SQLPOINTER)rgbRestData, 0, &cbRestData));
CHKRC(SQLSetStmtAttr(hstmt, SQL_SOPT_SS_PARAM_FOCUS, (SQLPOINTER)0, SQL_IS_INTEGER));
// Set cbParamLength to SQL_DATA_AT_EXEC to indicate the TVP parameter is bound as DAE.
cbParamLength = SQL_DATA_AT_EXEC;
rc = SQLExecute(hstmt);
if (rc == SQL_NEED_DATA) {
SQLPOINTER ptr = NULL;
SQLULEN cRows = 0;
rc = ::SQLParamData(hstmt, &ptr);
while (rc == SQL_NEED_DATA) {
if (ptr == (SQLPOINTER)1) {
// it is the TVP parameter
if (cRows == cMaxRows) {
// We finish sending the last row already.
CHKRC(::SQLPutData(hstmt, NULL, 0));
}
else {
// StrLen_or_IndPtr can be changed to SQL_DATA_AT_EXEC or to a byte length before sending
// the actual TVP rows. SQL_DATA_AT_EXEC means send DAE data.
llSeqNo = cRows;
cbSeqNo = sizeof(LONGLONG); // send as bound TVP column
lSeries = cRows + 100;
cbSeries = sizeof(LONG); // send as bound TVP column
cbRestData = SQL_DATA_AT_EXEC; // send as DAE TVP column
CHKRC(::SQLPutData(hstmt, (SQLPOINTER)1, 1));
cRows++;
}
}
else if (ptr == (SQLPOINTER)rgbRestData)
// varbinary(max) column. Send data in parts.
for ( int i = 0 ; i < 3 ; i++ ) {
// Obtain the data in part from somewhere, here we just set all bytes to 'a'.
::memset(rgbRestData, 'a', sizeof(rgbRestData));
CHKRC(::SQLPutData(hstmt, (SQLPOINTER)rgbRestData, sizeof(rgbRestData)));
}
else
// handling other DAE parameters, but in our case, we don't have other DAE parameters.
goto EXIT;
rc = ::SQLParamData(hstmt, &ptr);
}
}
if (hstmt)
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
if (hdbc) {
SQLDisconnect(hdbc);
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
}
if (henv)
SQLFreeHandle(SQL_HANDLE_ENV, henv);
EXIT:
if (!SUCCESS(rc)) {
if (hstmt)
PrintError(SQL_HANDLE_STMT, hstmt);
if (hdbc)
PrintError(SQL_HANDLE_DBC, hdbc);
if(henv)
PrintError(SQL_HANDLE_ENV, henv);
}
}
Przykład
Description
W przykładzie pokazano, którego można użyć wiersza strumieniowe przesyłanie wielu wierszy na wywołanie SQLPutData, z TVP ODBC, podobnie jak BCP.exe można użyć do załadowania danych do bazy danych.
Przed budynku próbki, należy zmienić nazwa serwera w ciąg połączenia.
Musisz mieć SQL Server 2008 Dodatek SP1 do uruchomienia tej próbki.
W przykładzie użyto domyślna baza danych.Przed uruchomieniem w tym przykładzie, uruchom następujące polecenia w bazie danych, który będzie używany:
create table MCLOG (
biSeqNo bigint,
iSeries int,
bmRestData varbinary(max)
)
go
-- Table type definition
create type MCLOGType
as table(biSeqNo bigint, iSeries int, bmRestData varbinary(max) )
go
-- Insert procedure
create procedure MCLOGInsert (@TableVariable MCLOGType READONLY)
as
insert into MCLog(biSeqNo, iSeries, bmRestData)
select biSeqNo, iSeries, bmRestData from @TableVariable
go
Code
#define UNICODE
#define _UNICODE
#define _SQLNCLI_ODBC_
#include <windows.h>
#include <tchar.h>
#include <sqlext.h>
#include "sqlncli.h"
// link to sqlncli10.lib
#define SUCCESS(x) ( \
!((x) & 0xFFFE) \
)
#define CHKRC(stmt) { \
rc = (stmt); \
if (!SUCCESS(rc)) { \
_tprintf(_T(#stmt) _T(" failed with rc = %ld\r\n"), rc); \
goto EXIT; \
} \
};
void PrintError(SQLSMALLINT HandleType, SQLHANDLE Handle) {
RETCODE rc = SQL_SUCCESS;
SQLTCHAR szSqlState[6];
SQLTCHAR szMessage[1024];
SQLSMALLINT i = 1;
SQLSMALLINT msgLen = 0;
SQLINTEGER NativeError;
i = 1;
while ( (rc = SQLGetDiagRec(HandleType, Handle, i, szSqlState, &NativeError, szMessage, sizeof(szMessage)/sizeof(SQLTCHAR), &msgLen)) != SQL_NO_DATA) {
if (!SUCCESS(rc))
break;
szMessage[msgLen] = 0;
szSqlState[5] = 0;
_tprintf(_T("SQLState=%s, NativeError=%ld, Message=%s\r\n"), szSqlState, NativeError, szMessage);
i++;
}
}
int main() {
RETCODE rc = SQL_SUCCESS;
HENV henv = SQL_NULL_HENV;
HDBC hdbc = SQL_NULL_HDBC;
SQLHSTMT hstmt = SQL_NULL_HSTMT;
SQLTCHAR * pszConnection = _T("DRIVER={SQL Server Native Client 10.0};Server=MyServer;Trusted_Connection=Yes;");
// insert one TVP parameter
SQLTCHAR * pszInsertStmt = _T("{call MCLOGInsert(?)}");
SQLLEN cbParamLength;
SQLULEN cMaxRows = 9;
CHKRC(SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HENV, &henv));
CHKRC(SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0));
CHKRC(SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc));
CHKRC(SQLSetConnectAttr( hdbc, SQL_ATTR_LOGIN_TIMEOUT, reinterpret_cast<SQLPOINTER>(60), SQL_IS_UINTEGER));
CHKRC(SQLDriverConnect( hdbc, NULL, pszConnection, SQL_NTS, NULL, 0, NULL, SQL_DRIVER_NOPROMPT));
CHKRC(SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt));
CHKRC(SQLPrepare(hstmt, pszInsertStmt, SQL_NTS));
// Bind the first parameter
CHKRC(SQLBindParameter( hstmt, 1, SQL_PARAM_INPUT, SQL_C_DEFAULT, SQL_SS_TABLE, cMaxRows, 0, (SQLPOINTER)1, 0, &cbParamLength));
/*
// If the stored procedure is executed as T-SQL ("exec sp_insert ?, ?"), then, supply the type name.
CHKRC(SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_DEFAULT, SQL_SS_TABLE, cMaxRows, 0, (SQLPOINTER)lpszTVPParamType, SQL_NTS, &cbParamLengths));
*/
// bind TVP columns.
CHKRC(SQLSetStmtAttr( hstmt, SQL_SOPT_SS_PARAM_FOCUS, (SQLPOINTER)1, SQL_IS_INTEGER));
// For the first and the second TVP columns (bigint, int), always send them as bound.
// For the third column varbinary(max), either send them as bound or DAE.
const size_t ARRAY_SIZE = 3;
LONGLONG llSeqNo[ARRAY_SIZE];
SQLLEN cbSeqNo[ARRAY_SIZE] = {sizeof(LONGLONG), sizeof(LONGLONG), sizeof(LONGLONG)};
LONG lSeries[ARRAY_SIZE];
SQLLEN cbSeries[ARRAY_SIZE] = {sizeof(LONG), sizeof(LONG), sizeof(LONG)};
BYTE rgbRestData[ARRAY_SIZE][2048];
SQLLEN cbRestData[ARRAY_SIZE] = {sizeof(rgbRestData[0]), sizeof(rgbRestData[0]), sizeof(rgbRestData[0])};
SQLUSMALLINT iColumn = 1;
// Bind biSeqNo
CHKRC(SQLBindParameter( hstmt, iColumn, SQL_PARAM_INPUT, SQL_C_SBIGINT, SQL_BIGINT, sizeof(LONGLONG), 0, (SQLPOINTER)&llSeqNo, sizeof(llSeqNo[0]), cbSeqNo));
// Bind iSeries
iColumn++;
CHKRC(SQLBindParameter( hstmt, iColumn, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, sizeof(LONG), 0, (SQLPOINTER)&lSeries, sizeof(lSeries[0]), cbSeries));
// Bind bmRestData
iColumn++;
CHKRC(SQLBindParameter(hstmt, iColumn, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_VARBINARY, 0, 0, (SQLPOINTER)rgbRestData, sizeof(rgbRestData[0]), cbRestData));
CHKRC(SQLSetStmtAttr(hstmt, SQL_SOPT_SS_PARAM_FOCUS, (SQLPOINTER)0, SQL_IS_INTEGER));
// Set cbParamLength to SQL_DATA_AT_EXEC to indicate the TVP parameter is bound as DAE.
cbParamLength = SQL_DATA_AT_EXEC;
rc = SQLExecute(hstmt);
if (rc == SQL_NEED_DATA) {
SQLPOINTER ptr = NULL;
SQLUINTEGER cRows = 0;
rc = ::SQLParamData(hstmt, &ptr);
while (rc == SQL_NEED_DATA) {
if (ptr == (SQLPOINTER)1) {
// it is the TVP parameter
if (cRows >= cMaxRows) {
// We finish sending the last row already.
CHKRC(::SQLPutData(hstmt, NULL, 0));
}
else {
// Obtaining row data from somewhere. In this case we will fill 3 rows.
for (size_t i = 0; i < ARRAY_SIZE; i++) {
llSeqNo[i] = cRows + i + 1;
lSeries[i] = llSeqNo[i] * 10;
// Now fill the varbinary(max) column. Assume that the even row can't be fit into
// the buffer provided as send them as DAE.
if (!((cRows + i) % 2)) {
// SQL_DATA_AT_EXEC means send DAE data.
cbRestData[i] = SQL_DATA_AT_EXEC;
}
else {
// data can fit into the buffer, then copy the data to the buffer directly.
cbRestData[i] = 100;
::memset(&rgbRestData[i], 'b', cbRestData[i]);
}
}
CHKRC(::SQLPutData(hstmt, (SQLPOINTER)1, ARRAY_SIZE));
cRows += ARRAY_SIZE;
}
}
else if ((SQLPOINTER)&rgbRestData[0] <= ptr && ptr <= (SQLPOINTER)&rgbRestData[ARRAY_SIZE-1]) {
// it is varbinary(max) column
// Send data in parts.
for (int i = 0; i < 3; i++) {
// Obtain the data in part from somewhere, here we just set all bytes to 'a'.
::memset(ptr, 'a', sizeof(rgbRestData[0]));
CHKRC(::SQLPutData(hstmt, (SQLPOINTER)ptr, sizeof(rgbRestData[0])));
}
}
else {
// handling other DAE parameters, but in our case, we don't have other DAE parameters.
goto EXIT;
}
rc = ::SQLParamData(hstmt, &ptr);
}
}
EXIT:
if (!SUCCESS(rc)) {
if (hstmt)
PrintError(SQL_HANDLE_STMT, hstmt);
if (hdbc)
PrintError(SQL_HANDLE_DBC, hdbc);
if(henv)
PrintError(SQL_HANDLE_ENV, henv);
}
if (hstmt)
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
if (hdbc) {
SQLDisconnect(hdbc);
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
}
if (henv)
SQLFreeHandle(SQL_HANDLE_ENV, henv);
}
Historia zmian
Microsoft Learning |
|---|
Dodaje próbki. |