/********************************************************************** * 打开轻量化CN后执行该程序,所有的select 1的期望结果应该是成功,但是在主键 * 冲突的错误报出来后,就会失败。原因可能与SAVEPOINT未释放有关(猜测) ***********************************************************************/ #include #include #include #include #include #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; }