231 lines
8.8 KiB
C
231 lines
8.8 KiB
C
/**********************************************************************
|
|
* 打开轻量化CN后执行该程序,所有的select 1的期望结果应该是成功,但是在主键
|
|
* 冲突的错误报出来后,就会失败。原因可能与SAVEPOINT未释放有关(猜测)
|
|
***********************************************************************/
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <sql.h>
|
|
#include <sqlext.h>
|
|
#include <string.h>
|
|
#include "common.h"
|
|
|
|
#define CHECK_ERROR(e, s, h, t) ({\
|
|
if (e!=SQL_SUCCESS && e != SQL_SUCCESS_WITH_INFO) \
|
|
{\
|
|
fprintf(stderr, "FAILED:\t");\
|
|
extract_error(s, h, t); \
|
|
exit(-1); \
|
|
}\
|
|
else\
|
|
{\
|
|
printf("OK:\t%s\n", s);\
|
|
}\
|
|
})
|
|
|
|
|
|
void extract_error(char *fn, SQLHANDLE handle, SQLSMALLINT type)
|
|
{
|
|
SQLINTEGER i = 0;
|
|
SQLINTEGER NativeError;
|
|
SQLCHAR SQLState[ 7 ];
|
|
SQLCHAR MessageText[256];
|
|
SQLSMALLINT TextLength;
|
|
SQLRETURN ret;
|
|
|
|
fprintf(stderr, "The driver reported the following error %s\n", fn);
|
|
if (NULL == handle)
|
|
return;
|
|
do
|
|
{
|
|
ret = SQLGetDiagRec(type, handle, ++i, SQLState, &NativeError,
|
|
MessageText, sizeof(MessageText), &TextLength);
|
|
if (SQL_SUCCEEDED(ret)) {
|
|
printf("[SQLState:%s]:[%ldth error]:[NativeError:%ld]: %s\n",
|
|
SQLState, (long) i, (long) NativeError, MessageText);
|
|
}
|
|
}
|
|
while( ret == SQL_SUCCESS );
|
|
}
|
|
|
|
void Exec(SQLHDBC hdbc, SQLCHAR* sql)
|
|
{
|
|
SQLRETURN retcode; // Return status
|
|
SQLHSTMT hstmt = SQL_NULL_HSTMT; // Statement handle
|
|
SQLCHAR loginfo[2048];
|
|
|
|
// Allocate Statement Handle
|
|
retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
|
|
CHECK_ERROR(retcode, "SQLAllocHandle(SQL_HANDLE_STMT)",
|
|
hstmt, SQL_HANDLE_STMT);
|
|
|
|
// Prepare Statement
|
|
retcode = SQLPrepare(hstmt, (SQLCHAR*) sql, SQL_NTS);
|
|
sprintf((char*)loginfo, "SQLPrepare log: %s", (char*)sql);
|
|
CHECK_ERROR(retcode, loginfo, hstmt, SQL_HANDLE_STMT);
|
|
|
|
retcode = SQLExecute(hstmt);
|
|
sprintf((char*)loginfo, "SQLExecute stmt log: %s", (char*)sql);
|
|
CHECK_ERROR(retcode, loginfo, hstmt, SQL_HANDLE_STMT);
|
|
retcode = SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
|
|
sprintf((char*)loginfo, "SQLFreeHandle stmt log: %s", (char*)sql);
|
|
CHECK_ERROR(retcode, loginfo, hstmt, SQL_HANDLE_STMT);
|
|
}
|
|
|
|
int test (const SQLCHAR *dsn, int batchCount, int ignoreCount) {
|
|
|
|
SQLHENV henv = SQL_NULL_HENV; // Environment
|
|
SQLHDBC hdbc = SQL_NULL_HDBC; // Connection handle
|
|
SQLLEN rowsCount = 0;
|
|
|
|
|
|
SQLRETURN retcode; // Return status
|
|
|
|
SQLCHAR loginfo[2048];
|
|
|
|
test_connect();
|
|
henv = env;
|
|
hdbc = conn;
|
|
|
|
retcode = SQLSetConnectAttr(hdbc, SQL_ATTR_AUTOCOMMIT,
|
|
(SQLPOINTER)(1), 0);
|
|
CHECK_ERROR(retcode, "SQLSetConnectAttr(SQL_ATTR_AUTOCOMMIT)",
|
|
hdbc, SQL_HANDLE_DBC);
|
|
|
|
// init table info.
|
|
Exec(hdbc, "drop table if exists test_odbc_batch_insert");
|
|
Exec(hdbc, "create table test_odbc_batch_insert(id int primary key, col varchar2(50))");
|
|
|
|
// Batch insert here:
|
|
{
|
|
SQLRETURN retcode; // Return status
|
|
SQLHSTMT hstmtinesrt = SQL_NULL_HSTMT; // Statement handle
|
|
int i;
|
|
SQLCHAR *sql = NULL;
|
|
SQLINTEGER *ids = NULL;
|
|
SQLCHAR *cols = NULL;
|
|
SQLLEN *bufLenIds = NULL;
|
|
SQLLEN *bufLenCols = NULL;
|
|
SQLUSMALLINT *operptr = NULL;
|
|
SQLUSMALLINT *statusptr = NULL;
|
|
SQLULEN process = 0;
|
|
|
|
ids = (SQLINTEGER*)malloc(sizeof(ids[0]) * batchCount);
|
|
cols = (SQLCHAR*)malloc(sizeof(cols[0]) * batchCount * 50);
|
|
bufLenIds = (SQLLEN*)malloc(sizeof(bufLenIds[0]) * batchCount);
|
|
bufLenCols = (SQLLEN*)malloc(sizeof(bufLenCols[0]) * batchCount);
|
|
operptr = (SQLUSMALLINT*)malloc(sizeof(operptr[0]) * batchCount);
|
|
memset(operptr, 0, sizeof(operptr[0]) * batchCount);
|
|
statusptr = (SQLUSMALLINT*)malloc(sizeof(statusptr[0]) * batchCount);
|
|
memset(statusptr, 88, sizeof(statusptr[0]) * batchCount);
|
|
|
|
if (NULL == ids || NULL == cols || NULL == bufLenCols || NULL == bufLenIds)
|
|
{
|
|
fprintf(stderr, "FAILED:\tmalloc data memory failed\n");
|
|
goto exit;
|
|
}
|
|
|
|
for (int i = 0; i < batchCount; i++)
|
|
{
|
|
ids[i] = i;
|
|
sprintf(cols + 50 * i, "column test value %d", i);
|
|
bufLenIds[i] = sizeof(ids[i]);
|
|
bufLenCols[i] = strlen(cols + 50 * i);
|
|
operptr[i] = (i < ignoreCount) ? SQL_PARAM_IGNORE : SQL_PARAM_PROCEED;
|
|
}
|
|
|
|
// Allocate Statement Handle
|
|
retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmtinesrt);
|
|
CHECK_ERROR(retcode, "SQLAllocHandle(SQL_HANDLE_STMT)",
|
|
hstmtinesrt, SQL_HANDLE_STMT);
|
|
|
|
// Prepare Statement
|
|
sql = (SQLCHAR*)"insert into test_odbc_batch_insert values(?, ?)";
|
|
retcode = SQLPrepare(hstmtinesrt, (SQLCHAR*) sql, SQL_NTS);
|
|
sprintf((char*)loginfo, "SQLPrepare log: %s", (char*)sql);
|
|
CHECK_ERROR(retcode, loginfo, hstmtinesrt, SQL_HANDLE_STMT);
|
|
|
|
retcode = SQLSetStmtAttr(hstmtinesrt, SQL_ATTR_PARAMSET_SIZE, (SQLPOINTER)batchCount, sizeof(batchCount));
|
|
CHECK_ERROR(retcode, "SQLSetStmtAttr", hstmtinesrt, SQL_HANDLE_STMT);
|
|
|
|
retcode = SQLBindParameter(hstmtinesrt, 1, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, sizeof(ids[0]), 0,&(ids[0]), 0, bufLenIds);
|
|
CHECK_ERROR(retcode, "SQLBindParameter for id", hstmtinesrt, SQL_HANDLE_STMT);
|
|
|
|
retcode = SQLBindParameter(hstmtinesrt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, 50, 50, cols, 50, bufLenCols);
|
|
CHECK_ERROR(retcode, "SQLBindParameter for cols", hstmtinesrt, SQL_HANDLE_STMT);
|
|
|
|
retcode = SQLSetStmtAttr(hstmtinesrt, SQL_ATTR_PARAMS_PROCESSED_PTR, (SQLPOINTER)&process, sizeof(process));
|
|
CHECK_ERROR(retcode, "SQLSetStmtAttr for SQL_ATTR_PARAMS_PROCESSED_PTR", hstmtinesrt, SQL_HANDLE_STMT);
|
|
|
|
retcode = SQLSetStmtAttr(hstmtinesrt, SQL_ATTR_PARAM_STATUS_PTR, (SQLPOINTER)statusptr, sizeof(statusptr[0]) * batchCount);
|
|
CHECK_ERROR(retcode, "SQLSetStmtAttr for SQL_ATTR_PARAM_STATUS_PTR", hstmtinesrt, SQL_HANDLE_STMT);
|
|
|
|
retcode = SQLSetStmtAttr(hstmtinesrt, SQL_ATTR_PARAM_OPERATION_PTR, (SQLPOINTER)operptr, sizeof(operptr[0]) * batchCount);
|
|
CHECK_ERROR(retcode, "SQLSetStmtAttr for SQL_ATTR_PARAM_OPERATION_PTR", hstmtinesrt, SQL_HANDLE_STMT);
|
|
|
|
retcode = SQLExecute(hstmtinesrt);
|
|
sprintf((char*)loginfo, "SQLExecute stmt log: %s", (char*)sql);
|
|
CHECK_ERROR(retcode, loginfo, hstmtinesrt, SQL_HANDLE_STMT);
|
|
|
|
retcode = SQLRowCount(hstmtinesrt, &rowsCount);
|
|
CHECK_ERROR(retcode, "SQLRowCount execution", hstmtinesrt, SQL_HANDLE_STMT);
|
|
|
|
if (rowsCount != (batchCount - ignoreCount))
|
|
{
|
|
sprintf(loginfo, "(batchCount - ignoreCount)(%d) != rowsCount(%d)", (batchCount - ignoreCount), rowsCount);
|
|
CHECK_ERROR(SQL_ERROR, loginfo, NULL, SQL_HANDLE_STMT);
|
|
}
|
|
else
|
|
{
|
|
sprintf(loginfo, "(batchCount - ignoreCount)(%d) == rowsCount(%d)", (batchCount - ignoreCount), rowsCount);
|
|
CHECK_ERROR(SQL_SUCCESS, loginfo, NULL, SQL_HANDLE_STMT);
|
|
}
|
|
|
|
if (rowsCount != process)
|
|
{
|
|
sprintf(loginfo, "process(%d) != rowsCount(%d)", process, rowsCount);
|
|
CHECK_ERROR(SQL_ERROR, loginfo, NULL, SQL_HANDLE_STMT);
|
|
}
|
|
else
|
|
{
|
|
sprintf(loginfo, "process(%d) == rowsCount(%d)", process, rowsCount);
|
|
CHECK_ERROR(SQL_SUCCESS, loginfo, NULL, SQL_HANDLE_STMT);
|
|
}
|
|
|
|
for (int i = 0; i < batchCount; i++)
|
|
{
|
|
if (i < ignoreCount)
|
|
{
|
|
if (statusptr[i] != SQL_PARAM_UNUSED)
|
|
{
|
|
sprintf(loginfo, "statusptr[%d](%d) != SQL_PARAM_UNUSED", i, statusptr[i]);
|
|
CHECK_ERROR(SQL_ERROR, loginfo, NULL, SQL_HANDLE_STMT);
|
|
}
|
|
}
|
|
else if (statusptr[i] != SQL_PARAM_SUCCESS)
|
|
{
|
|
sprintf(loginfo, "statusptr[%d](%d) != SQL_PARAM_SUCCESS", i, statusptr[i]);
|
|
CHECK_ERROR(SQL_ERROR, loginfo, NULL, SQL_HANDLE_STMT);
|
|
}
|
|
}
|
|
|
|
retcode = SQLFreeHandle(SQL_HANDLE_STMT, hstmtinesrt);
|
|
sprintf((char*)loginfo, "SQLFreeHandle hstmtinesrt");
|
|
CHECK_ERROR(retcode, loginfo, hstmtinesrt, SQL_HANDLE_STMT);
|
|
}
|
|
|
|
|
|
exit:
|
|
printf ("\nComplete.\n");
|
|
test_disconnect();
|
|
|
|
return 0;
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
test("gaussdb", 7000, 3);
|
|
test("gaussdb", 7, 0);
|
|
test("gaussdb", 7, 7);
|
|
return 0;
|
|
}
|