powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / C++ [игнор отключен] [закрыт для гостей] / SQLBulkOperations with Long Data
4 сообщений из 4, страница 1 из 1
SQLBulkOperations with Long Data
    #32771514
vadik_malyshev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Тема SQLBulkOperations

вопрос
есть табличка

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
create table test_table
(
	id int primary key,
	descr varchar( 255 ),
	strData text,
	binData image
)

--drop table test_table
нужно быстро залить данными с использованием SQLBulkOperations .
с обычными типами проблем не возникает.

А вот с этими беда.

strData text,
binData image

Я уже задолбался. Читал в msdm Providing Long Data for Bulk Inserts and Updates, если честно я там не могу понять идеологию и последовательность вызовов. Как - то странно там это описывается. Или я тупой. Помогите плиз примерчиком.
...
Рейтинг: 0 / 0
SQLBulkOperations with Long Data
    #32771697
vadik_malyshev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Делаю примерно следующее:

Код: plaintext
1.
2.
3.
4.
5.
6.
create table test_table
(
	id int,
	binData image
)

--drop table test_table


Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
#include <stdio.h>
#include <windows.h>
#include <sql.h>
#include <sqlext.h>

#define NUM_ROWS         20 
#define BLOB_SIZE1       255 

typedef struct 
{
	SQLINTEGER  id;

} RowStruct;

int main (long argc, char* argv[])
{
	SQLHDBC     hdbc;
	SQLHENV     henv;
	SQLHSTMT    hstmt;

	SQLRETURN     rc =  0 ;
	SQLINTEGER	  i;

	rc = SQLAllocHandle (SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
	rc = SQLSetEnvAttr (henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3,  0 );
	rc = SQLAllocHandle (SQL_HANDLE_DBC, henv, &hdbc);
		
	rc = SQLConnect (hdbc, (SQLCHAR*)"my_test_dsn", SQL_NTS, (SQLCHAR*) "", SQL_NTS, (SQLCHAR*) "", SQL_NTS);

	/* Allocate the statement handle */
	rc = SQLAllocHandle (SQL_HANDLE_STMT, hdbc, &hstmt );

	/*Set the statement attributes*/
	rc = SQLSetStmtAttr (hstmt, SQL_ATTR_ROW_BIND_TYPE, (SQLPOINTER) sizeof(RowStruct),  0 );
	rc = SQLSetStmtAttr (hstmt, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER) NUM_ROWS,  0 );
	rc = SQLSetStmtAttr (hstmt, SQL_ATTR_ROW_BIND_OFFSET_PTR, (SQLPOINTER) &bindOffset,  0 );
	
	SQLINTEGER colBin= 2 ;
	SQLINTEGER lenBuff = SQL_DATA_AT_EXEC;

	/*Bind columns*/
	rc = SQLBindCol (hstmt,  1 , SQL_C_LONG, &rows[ 0 ].id,  0 ,  0 );
	rc = SQLBindCol (hstmt,  2 , SQL_C_BINARY, (SQLPOINTER)colBin,  0 ,&lenBuff); 
	
	//Initialise rows buffer
	for (i= 0 ; i<NUM_ROWS; i++)
	{
		rows[i].id = i+ 1 ;
	}

	/*Для упрощения использую один буфферок для всех вставляемых строк*/
	BYTE blobBuffer[BLOB_SIZE1]; 
	ZeroMemory(blobBuffer,sizeof blobBuffer);

	SQLPOINTER pToken;
	
	rc = SQLBulkOperations (hstmt, SQL_ADD);
	if(rc == SQL_NEED_DATA)
	{
		rc = SQLParamData(hstmt, &pToken);
		while (rc == SQL_NEED_DATA) 
		{	
			SQLINTEGER col = (SQLINTEGER)pToken;

			rc = SQLPutData(hstmt, blobBuffer, BLOB_SIZE1);
			rc = SQLParamData(hstmt, &pToken);
		}
	}

	...
}
Валиться при вызовах SQLParamData,SQLPutData.

Если второй столбец убрать из таблички и из запроса. и убрать из кода
SQLBindCol для второй колонки то все работает замечательно. И очень быстро.

Может кто-то делал что-то подобное и найдет здесь концептуальную ошибку?
И вообще буду признателен за любую информацию,
связанную с использованием SQLBulkOperations с длинными типами данных
...
Рейтинг: 0 / 0
SQLBulkOperations with Long Data
    #32772182
vadik_malyshev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Концептуальных ошибок нет.
вот работающий, правда на информиксе пример
всем спасибо за участие, может кому нибудь пригодиться этот опыт

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.
251.
252.
253.
254.
255.
256.
257.
258.
259.
260.
261.
262.
263.
264.
265.
266.
267.
268.
269.
270.
271.
272.
273.
274.
275.
276.
/***************************************************************************

	Используется:
	SQL Server:     Infomix 9.40 on HP_UX
	Драйвер ODBC    Infomix 3.81 32 bit   version 3.81.00.11267 IBM Corparation

	Таблица

	CREATE TABLE test_table
	(
		id int,
		binData byte
	)

	drop table test_table

	delete from  test_table where id<>1

	select * from test_table
***************************************************************************
*/

#include <stdio.h>
#include <windows.h>
#include <sql.h>
#include <sqlext.h>

#define BUFFER_LEN       255 
#define ERRMSG_LEN       200 
#define NUM_ROWS         200 
#define BLOB_SIZE1       589 

/*
	В SQLPutData можно отправлять только 
	по 56 байт за раз 
	(Но это ыявлено только для информикса,
	И скорее всего зависит от настроек)
	
	Почему то только 56!
	
	В этом и был прикол... 
	Наверно какойт то внутренний буффер.
	Но чтото уж слишком маленький
	Как его немного увеличить пока не нашел.
 */

#define INTERNAL_INFORMIX_PUTDATA_BUFFER  56 

typedef struct 
{
	SQLINTEGER  id;
	SQLINTEGER  cbId;
	SQLINTEGER  tag;
	SQLINTEGER  cbImage;
} RowStruct;

SQLINTEGER checkError (SQLRETURN rc, SQLSMALLINT handleType, SQLHANDLE handle, SQLCHAR* errmsg);

int main (long         argc,
          char*        argv[])
{
	/* Declare variables*/

	/* Handles */            
	SQLHDBC     hdbc;
	SQLHENV     henv;
	SQLHSTMT    hstmt;

	/* Miscellaneous variables */

	SQLRETURN     rc =  0 ;
	SQLINTEGER    i,in;

	RowStruct rows[NUM_ROWS];
	ZeroMemory(rows,sizeof rows);

	BYTE blobBuffer[BLOB_SIZE1]; 
	memset(blobBuffer, 30 ,sizeof blobBuffer);//Инициализируем чем попало
	blobBuffer[BLOB_SIZE1]= 0 ;

	SQLINTEGER  bindOffset =  0 ; 

	/* Allocate the Environment handle */
	rc = SQLAllocHandle (SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
	if (rc != SQL_SUCCESS)
	{
		fprintf (stdout, "Environment Handle Allocation failed\nExiting!!");
		return ( 1 );
	}

	/* Set the ODBC version to 3.0 */
	rc = SQLSetEnvAttr (henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3,  0 );
	if (checkError (rc, SQL_HANDLE_ENV, henv, (SQLCHAR *) "Error in Step 1 -- SQLSetEnvAttr failed\nExiting!!"))
		return ( 1 );

	/* Allocate the connection handle */
	rc = SQLAllocHandle (SQL_HANDLE_DBC, henv, &hdbc);
	if (checkError (rc, SQL_HANDLE_ENV, henv, (SQLCHAR *) "Error in Step 1 -- Connection Handle Allocation failed\nExiting!!"))
		return ( 1 );

	/* Connect to the database */
	rc = SQLConnect (hdbc, (SQLCHAR*)"ifx_tcp_inisrk_vadik", SQL_NTS, (SQLCHAR *) "", SQL_NTS, (SQLCHAR *) "", SQL_NTS);
	//rc = SQLConnect (hdbc, (SQLCHAR*)"sql_test_insert", SQL_NTS, (SQLCHAR *) "", SQL_NTS, (SQLCHAR *) "", SQL_NTS);
	if (checkError (rc, SQL_HANDLE_DBC, hdbc, (SQLCHAR *) "Error in Step 1 -- SQLDriverConnect failed\nExiting!!"))
		return ( 1 );

	/* Allocate the statement handle */
	rc = SQLAllocHandle (SQL_HANDLE_STMT, hdbc, &hstmt );
	if (checkError (rc, SQL_HANDLE_DBC, hdbc, (SQLCHAR *) "Error in Step 1 -- Statement Handle Allocation failed\nExiting!!"))
		return ( 1 );

	fprintf (stdout, "STEP 1 done...connected to database\n");

	/*
	rc = SQLSetStmtAttr(hstmt, SQL_ATTR_CURSOR_TYPE, (SQLPOINTER)SQL_CURSOR_KEYSET_DRIVEN, 0);
	if (checkError (rc, SQL_HANDLE_STMT, hstmt, (SQLCHAR *) "Error in Step 2 -- SQLSetStmtAttr failed for SQL_ATTR_CONCURRENCY\n"))
		goto Exit;
	*/

	/* Set the statement attribute SQL_ATTR_CONCURRENCY to SQL_CONCUR_LOCK */
	rc = SQLSetStmtAttr (hstmt, SQL_ATTR_CONCURRENCY, (SQLPOINTER) SQL_CONCUR_LOCK,  0 );
	if (checkError (rc, SQL_HANDLE_STMT, hstmt, (SQLCHAR *) "Error in Step 2 -- SQLSetStmtAttr failed for SQL_ATTR_CONCURRENCY\n"))
		goto Exit;
	

	/* Set the statement attribute SQL_ATTR_ROW_BIND_TYPE */
	rc = SQLSetStmtAttr (hstmt, SQL_ATTR_ROW_BIND_TYPE, (SQLPOINTER) sizeof(RowStruct),  0 );
	if (checkError (rc, SQL_HANDLE_STMT, hstmt, (SQLCHAR *) "Error in Step 2 -- SQLSetStmtAttr failed for SQL_ATTR_ROW_BIND_TYPE\n"))
		goto Exit;

	/* Set the statement attribute SQL_ATTR_ROW_ARRAY_SIZE to the number of rows to be bound */
	rc = SQLSetStmtAttr (hstmt, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER) NUM_ROWS,  0 );
	if (checkError (rc, SQL_HANDLE_STMT, hstmt, (SQLCHAR *) "Error in Step 2 -- SQLSetStmtAttr failed for SQL_ATTR_ROW_ARRAY_SIZE\n"))
		goto Exit;

	/* Set the statement attribute SQL_ATTR_ROW_BIND_OFFSET_PTR to the binding offset */
	rc = SQLSetStmtAttr (hstmt, SQL_ATTR_ROW_BIND_OFFSET_PTR, (SQLPOINTER) &bindOffset,  0 );
	if (checkError (rc, SQL_HANDLE_STMT, hstmt, (SQLCHAR *) "Error in Step 2 -- SQLSetStmtAttr failed for SQL_ATTR_ROW_BIND_OFFSET_PTR\n"))
		goto Exit;

	fprintf (stdout, "STEP 2 done...Statement attributes set\n");


	for (i= 0 ; i<NUM_ROWS; i++)
	{
		rows[i].id = i+ 1 ;
		rows[i].cbId = sizeof SQLINTEGER;
		rows[i].tag =  2 ;
		rows[i].cbImage = SQL_DATA_AT_EXEC;
	}

	/*Bind the result set columns*/
	rc = SQLBindCol (hstmt,  1 , SQL_C_LONG, &rows[ 0 ].id,  0 , &rows[ 0 ].cbId);
	if (checkError (rc, SQL_HANDLE_STMT, hstmt, (SQLCHAR *) "Error in Step 3 -- SQLBindCol failed (column 1)\n"))
		goto Exit;

	rc = SQLBindCol (hstmt,  2 , SQL_C_BINARY, (PTR)rows[ 0 ].tag,  0 ,&rows[ 0 ].cbImage); 
	if (checkError (rc, SQL_HANDLE_STMT, hstmt, (SQLCHAR *) "Error in Step 3 -- SQLBindCol failed (column 2)\n"))
		goto Exit;
	
	rc = SQLExecDirect (hstmt, (UCHAR *) "SELECT id, binData FROM test_table", SQL_NTS);
	if (checkError (rc, SQL_HANDLE_STMT, hstmt, (SQLCHAR *) "Error in Step 3 -- SQLExecDirect failed\n"))
		goto Exit;

	fprintf (stdout, "STEP 4 done...Values of new rows set in orders array\n");

	LARGE_INTEGER m_finish;
	LARGE_INTEGER m_start;

	{
	SQLINTEGER lbytes;
	SQLINTEGER cbBatch = INTERNAL_INFORMIX_PUTDATA_BUFFER;

	QueryPerformanceCounter(&m_start);
	{

		SQLPOINTER pToken= 0 ;
		rc = SQLBulkOperations (hstmt, SQL_ADD);
		if(rc == SQL_NEED_DATA)
		{
			rc = SQLParamData(hstmt, &pToken);
			while (rc == SQL_NEED_DATA) 
			{	
				SQLINTEGER tag = (SQLINTEGER)pToken;
				/*
					На основани данных записанного в поле tag
					инициализируем указатель на данные
					В этом примере для урощения используется 
					один буффер данных для всех вставляемых строк
				*/
				PBYTE Data = blobBuffer;
				lbytes = BLOB_SIZE1;

				while (lbytes > cbBatch) 
				{
					SQLPutData(hstmt, Data, cbBatch);
					Data+=cbBatch;
					lbytes -= cbBatch;
				}  
				SQLPutData(hstmt, Data, lbytes);
				
				rc = SQLParamData(hstmt, &pToken);
			}
		}
	}
	}

	QueryPerformanceCounter(&m_finish);

	if (checkError (rc, SQL_HANDLE_STMT, hstmt, (SQLCHAR *) "Error in Step 5 -- SQLBulkOperations\n"))
		goto Exit;

	fprintf (stdout, "STEP 5 done...New rows inserted in table 'test_table'\n");

	LARGE_INTEGER liFreq;
	QueryPerformanceFrequency(&liFreq);

	fprintf(stdout, "Insert %d rows duration %0.4f seconds", NUM_ROWS, ((double)(m_finish.QuadPart - m_start.QuadPart)/(double)liFreq.QuadPart));

	Exit:

	/* Close the statement handle */
	SQLFreeStmt (hstmt, SQL_CLOSE);

	/* Free the statement handle */
	SQLFreeHandle (SQL_HANDLE_STMT, hstmt);

	/* Disconnect from the data source */
	SQLDisconnect (hdbc);

	/* Free the environment handle and the database connection handle */
	SQLFreeHandle (SQL_HANDLE_DBC, hdbc);
	SQLFreeHandle (SQL_HANDLE_ENV, henv);

	fprintf (stdout,"\n\nHit <Enter> to terminate the program...\n\n");
	in = getchar ();
	return (rc);
}

SQLINTEGER checkError (SQLRETURN       rc,
                SQLSMALLINT     handleType,
				SQLHANDLE       handle,
				SQLCHAR*            errmsg)
{
    SQLRETURN       retcode = SQL_SUCCESS;

    SQLSMALLINT     errNum =  1 ;
	SQLCHAR		    sqlState[ 6 ];
    SQLINTEGER      nativeError;
	SQLCHAR		    errMsg[ERRMSG_LEN];
    SQLSMALLINT     textLengthPtr;
 

    if ((rc != SQL_SUCCESS) && (rc != SQL_SUCCESS_WITH_INFO))
    {
        while (retcode != SQL_NO_DATA)
        {
            retcode = SQLGetDiagRec (handleType, handle, errNum, sqlState, &nativeError, errMsg, ERRMSG_LEN, &textLengthPtr);

            if (retcode == SQL_INVALID_HANDLE)
            {
                fprintf (stderr, "checkError function was called with an invalid handle!!\n");
                return  1 ;
            }

            if ((retcode == SQL_SUCCESS) || (retcode == SQL_SUCCESS_WITH_INFO))
                fprintf (stderr, "ERROR: %d:  %s : %s \n", nativeError, sqlState, errMsg);

            errNum++;
        }

        fprintf (stderr, "%s\n", errmsg);
        return  1 ;   /* all errors on this handle have been reported */
    }
	else
		return  0 ;	/* no errors to report */}
...
Рейтинг: 0 / 0
SQLBulkOperations with Long Data
    #33062769
AlexandrFyodorov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Огромное Спасиба за предоставленный код. Разобравшись, я наконец то написал рабочие функции, которые сохраняют большой объем двоичной информации в поле image таблицы на SqlServer'ной базе.

typedef std::vector<float> tDataType;

BOOL _sql_UpdateRecords(int ID, tDataType &Target, SQLINTEGER strLen_or_indPtr)
{
//распределяем описатель запроса
sqlRet = SQLAllocHandle(SQL_HANDLE_STMT,hDBConn, &hSTMT);
if(isSUCCESS(hSTMT, SQL_HANDLE_STMT) != TRUE) return FALSE;

char sqlRequest[333];
sprintf(sqlRequest,"UPDATE RecordsData SET Data = ? WHERE ID = %d",ID);

#define MAX_DATA_LEN Target.size()
#define MAX_BUFFER_LEN MAX_DATA_LEN

sqlRet = SQLPrepare(hSTMT,(SQLCHAR*)sqlRequest,SQL_NTS);
if(isSUCCESS(hSTMT, SQL_HANDLE_STMT) != TRUE) return FALSE;

strLen_or_indPtr = SQL_DATA_AT_EXEC;

sqlRet = SQLBindParameter(hSTMT,1,SQL_PARAM_INPUT,SQL_C_BINARY,SQL_LONGVARBINARY, SQL_DESC_LENGTH,0,(SQLPOINTER)1,sizeof(float),&strLen_or_indPtr);
// ColumnSize = SQL_DESC_LENGTH


sqlRet = SQLExecute(hSTMT);


SQLPOINTER pToken;
SQLINTEGER bBatch = MAX_BUFFER_LEN;
SQLINTEGER bLeftData;//задать

if(sqlRet == SQL_NEED_DATA){
sqlRet = SQLParamData(hSTMT,&pToken);
while(sqlRet == SQL_NEED_DATA)
{
PFLOAT pData = (FLOAT*)&Target[0];//*/Data;
bLeftData = MAX_DATA_LEN;
while(bLeftData > bBatch){
//здесь
SQLPutData(hSTMT,pData,bBatch);
pData += bLeftData;
bLeftData -= bBatch;
}
SQLPutData(hSTMT,pData,bLeftData);
sqlRet = SQLParamData(hSTMT,&pToken);
}
}

//отвязываем параметры
sqlRet = SQLFreeStmt(hSTMT,SQL_RESET_PARAMS);
if(!isSUCCESS(hSTMT, SQL_HANDLE_STMT))return FALSE;

//освобождаем наш описатель запроса
sqlRet = SQLFreeHandle(SQL_HANDLE_STMT,hSTMT);
return isSUCCESS(hSTMT, SQL_HANDLE_STMT);
}

BOOL isSUCCESS(SQLHANDLE sqlHandle, SQLSMALLINT sqlHandleType)
{
strcpy(sqlRetMessage,"");
if(sqlRet != SQL_SUCCESS)
{
SQLCHAR SqlState[6];
SQLINTEGER NativeError;
SQLCHAR ErrMsg[SQL_MAX_MESSAGE_LENGTH];
int i = 1;

char ErrSmall[555];
SQLRETURN diagRet = 0;
if(sqlRet >= -1)
while(SQLGetDiagRec(sqlHandleType, sqlHandle, i,SqlState,&NativeError,ErrMsg,sizeof(ErrMsg),NULL) != SQL_NO_DATA)
{
sprintf(ErrSmall,"\nDIAG: %d,\n SQLSTATE: %s,\n NativeError: %d,\n ErrMsg: %s\n\n",i,SqlState,NativeError,ErrMsg);
i++;
//Далее происходит следующее
//строчка из ErrSmall добавляется в sqlRetMessage
strcpy(sqlRetMessage,ErrSmall);
}

if(sqlRet != SQL_SUCCESS_WITH_INFO)
return FALSE;
}
return TRUE;
}
...
Рейтинг: 0 / 0
4 сообщений из 4, страница 1 из 1
Форумы / C++ [игнор отключен] [закрыт для гостей] / SQLBulkOperations with Long Data
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]