示例:常用功能和批量绑定

    批量绑定示例代码

    1. * 请在数据源中打开UseBatchProtocol,同时指定数据库中参数support_batch_bind
    2. * 为on
    3. * CHECK_ERROR的作用是检查并打印错误信息。
    4. * 此示例将与用户交互式获取DSN、模拟的数据量,忽略的数据量,并将最终数据入库到test_odbc_batch_insert中
    5. ***********************************************************************/
    6. #include <stdio.h>
    7. #include <stdlib.h>
    8. #include <sql.h>
    9. #include <sqlext.h>
    10. #include <string.h>
    11. void Exec(SQLHDBC hdbc, SQLCHAR* sql)
    12. {
    13. SQLRETURN retcode; // Return status
    14. SQLHSTMT hstmt = SQL_NULL_HSTMT; // Statement handle
    15. SQLCHAR loginfo[2048];
    16. // Allocate Statement Handle
    17. retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
    18. if (!SQL_SUCCEEDED(retcode)) {
    19. printf("SQLAllocHandle(SQL_HANDLE_STMT) failed");
    20. return;
    21. }
    22. // Prepare Statement
    23. retcode = SQLPrepare(hstmt, (SQLCHAR*) sql, SQL_NTS);
    24. sprintf((char*)loginfo, "SQLPrepare log: %s", (char*)sql);
    25. if (!SQL_SUCCEEDED(retcode)) {
    26. printf("SQLPrepare(hstmt, (SQLCHAR*) sql, SQL_NTS) failed");
    27. return;
    28. }
    29. // Execute Statement
    30. retcode = SQLExecute(hstmt);
    31. sprintf((char*)loginfo, "SQLExecute stmt log: %s", (char*)sql);
    32. if (!SQL_SUCCEEDED(retcode)) {
    33. printf("SQLExecute(hstmt) failed");
    34. return;
    35. }
    36. // Free Handle
    37. retcode = SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
    38. sprintf((char*)loginfo, "SQLFreeHandle stmt log: %s", (char*)sql);
    39. if (!SQL_SUCCEEDED(retcode)) {
    40. printf("SQLFreeHandle(SQL_HANDLE_STMT, hstmt) failed");
    41. return;
    42. }
    43. }
    44. int main ()
    45. {
    46. SQLHENV henv = SQL_NULL_HENV;
    47. SQLHDBC hdbc = SQL_NULL_HDBC;
    48. int batchCount = 1000; // 批量绑定的数据量
    49. SQLLEN rowsCount = 0;
    50. int ignoreCount = 0; // 批量绑定的数据中,不要入库的数据量
    51. SQLRETURN retcode;
    52. SQLCHAR dsn[1024] = {'\0'};
    53. SQLCHAR loginfo[2048];
    54. do
    55. {
    56. if (ignoreCount > batchCount)
    57. {
    58. printf("ignoreCount(%d) should be less than batchCount(%d)\n", ignoreCount, batchCount);
    59. }
    60. }while(ignoreCount > batchCount);
    61. retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
    62. if (!SQL_SUCCEEDED(retcode)) {
    63. printf("SQLAllocHandle failed");
    64. goto exit;
    65. }
    66. // Set ODBC Verion
    67. retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION,
    68. (SQLPOINTER*)SQL_OV_ODBC3, 0);
    69. if (!SQL_SUCCEEDED(retcode)) {
    70. printf("SQLSetEnvAttr failed");
    71. goto exit;
    72. }
    73. // Allocate Connection
    74. retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
    75. if (!SQL_SUCCEEDED(retcode)) {
    76. printf("SQLAllocHandle failed");
    77. goto exit;
    78. }
    79. // Set Login Timeout
    80. retcode = SQLSetConnectAttr(hdbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0);
    81. if (!SQL_SUCCEEDED(retcode)) {
    82. printf("SQLSetConnectAttr failed");
    83. goto exit;
    84. }
    85. // Set Auto Commit
    86. retcode = SQLSetConnectAttr(hdbc, SQL_ATTR_AUTOCOMMIT,
    87. (SQLPOINTER)(1), 0);
    88. if (!SQL_SUCCEEDED(retcode)) {
    89. goto exit;
    90. }
    91. // Connect to DSN
    92. // gaussdb替换成用户所使用的数据源名称
    93. sprintf(loginfo, "SQLConnect(DSN:%s)", dsn);
    94. retcode = SQLConnect(hdbc, (SQLCHAR*) "gaussdb", SQL_NTS,
    95. (SQLCHAR*) NULL, 0, NULL, 0);
    96. if (!SQL_SUCCEEDED(retcode)) {
    97. printf("SQLConnect failed");
    98. goto exit;
    99. }
    100. // init table info.
    101. Exec(hdbc, "drop table if exists test_odbc_batch_insert");
    102. Exec(hdbc, "create table test_odbc_batch_insert(id int primary key, col varchar2(50))");
    103. // 下面的代码根据用户输入的数据量,构造出将要入库的数据:
    104. {
    105. SQLRETURN retcode;
    106. SQLHSTMT hstmtinesrt = SQL_NULL_HSTMT;
    107. int i;
    108. SQLCHAR *sql = NULL;
    109. SQLINTEGER *ids = NULL;
    110. SQLCHAR *cols = NULL;
    111. SQLLEN *bufLenIds = NULL;
    112. SQLLEN *bufLenCols = NULL;
    113. SQLUSMALLINT *operptr = NULL;
    114. SQLUSMALLINT *statusptr = NULL;
    115. SQLULEN process = 0;
    116. // 这里是按列构造,每个字段的内存连续存放在一起。
    117. ids = (SQLINTEGER*)malloc(sizeof(ids[0]) * batchCount);
    118. cols = (SQLCHAR*)malloc(sizeof(cols[0]) * batchCount * 50);
    119. // 这里是每个字段中,每一行数据的内存长度。
    120. bufLenIds = (SQLLEN*)malloc(sizeof(bufLenIds[0]) * batchCount);
    121. bufLenCols = (SQLLEN*)malloc(sizeof(bufLenCols[0]) * batchCount);
    122. // 该行是否需要被处理,SQL_PARAM_IGNORE 或 SQL_PARAM_PROCEED
    123. operptr = (SQLUSMALLINT*)malloc(sizeof(operptr[0]) * batchCount);
    124. memset(operptr, 0, sizeof(operptr[0]) * batchCount);
    125. // 该行的处理结果。
    126. // 注:由于数据库中处理方式是同一语句隶属同一事务中,所以如果出错,那么待处理数据都将是出错的,并不会部分入库。
    127. statusptr = (SQLUSMALLINT*)malloc(sizeof(statusptr[0]) * batchCount);
    128. memset(statusptr, 88, sizeof(statusptr[0]) * batchCount);
    129. if (NULL == ids || NULL == cols || NULL == bufLenCols || NULL == bufLenIds)
    130. {
    131. fprintf(stderr, "FAILED:\tmalloc data memory failed\n");
    132. goto exit;
    133. }
    134. for (int i = 0; i < batchCount; i++)
    135. {
    136. ids[i] = i;
    137. sprintf(cols + 50 * i, "column test value %d", i);
    138. bufLenIds[i] = sizeof(ids[i]);
    139. bufLenCols[i] = strlen(cols + 50 * i);
    140. operptr[i] = (i < ignoreCount) ? SQL_PARAM_IGNORE : SQL_PARAM_PROCEED;
    141. }
    142. // Allocate Statement Handle
    143. retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmtinesrt);
    144. if (!SQL_SUCCEEDED(retcode)) {
    145. printf("SQLAllocHandle failed");
    146. goto exit;
    147. }
    148. // Prepare Statement
    149. sql = (SQLCHAR*)"insert into test_odbc_batch_insert values(?, ?)";
    150. retcode = SQLPrepare(hstmtinesrt, (SQLCHAR*) sql, SQL_NTS);
    151. sprintf((char*)loginfo, "SQLPrepare log: %s", (char*)sql);
    152. if (!SQL_SUCCEEDED(retcode)) {
    153. printf("SQLPrepare failed");
    154. goto exit;
    155. }
    156. retcode = SQLSetStmtAttr(hstmtinesrt, SQL_ATTR_PARAMSET_SIZE, (SQLPOINTER)batchCount, sizeof(batchCount));
    157. if (!SQL_SUCCEEDED(retcode)) {
    158. printf("SQLSetStmtAttr failed");
    159. goto exit;
    160. }
    161. retcode = SQLBindParameter(hstmtinesrt, 1, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, sizeof(ids[0]), 0,&(ids[0]), 0, bufLenIds);
    162. if (!SQL_SUCCEEDED(retcode)) {
    163. printf("SQLBindParameter failed");
    164. goto exit;
    165. }
    166. retcode = SQLBindParameter(hstmtinesrt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, 50, 50, cols, 50, bufLenCols);
    167. if (!SQL_SUCCEEDED(retcode)) {
    168. printf("SQLBindParameter failed");
    169. goto exit;
    170. }
    171. retcode = SQLSetStmtAttr(hstmtinesrt, SQL_ATTR_PARAMS_PROCESSED_PTR, (SQLPOINTER)&process, sizeof(process));
    172. if (!SQL_SUCCEEDED(retcode)) {
    173. printf("SQLSetStmtAttr failed");
    174. goto exit;
    175. }
    176. retcode = SQLSetStmtAttr(hstmtinesrt, SQL_ATTR_PARAM_STATUS_PTR, (SQLPOINTER)statusptr, sizeof(statusptr[0]) * batchCount);
    177. goto exit;
    178. }
    179. retcode = SQLSetStmtAttr(hstmtinesrt, SQL_ATTR_PARAM_OPERATION_PTR, (SQLPOINTER)operptr, sizeof(operptr[0]) * batchCount);
    180. if (!SQL_SUCCEEDED(retcode)) {
    181. printf("SQLSetStmtAttr failed");
    182. goto exit;
    183. }
    184. retcode = SQLExecute(hstmtinesrt);
    185. sprintf((char*)loginfo, "SQLExecute stmt log: %s", (char*)sql);
    186. if (!SQL_SUCCEEDED(retcode)) {
    187. printf("SQLExecute(hstmtinesrt) failed");
    188. goto exit;
    189. retcode = SQLRowCount(hstmtinesrt, &rowsCount);
    190. if (!SQL_SUCCEEDED(retcode)) {
    191. printf("SQLRowCount failed");
    192. goto exit;
    193. }
    194. if (rowsCount != (batchCount - ignoreCount))
    195. {
    196. sprintf(loginfo, "(batchCount - ignoreCount)(%d) != rowsCount(%d)", (batchCount - ignoreCount), rowsCount);
    197. if (!SQL_SUCCEEDED(retcode)) {
    198. printf("SQLExecute failed");
    199. goto exit;
    200. }
    201. }
    202. else
    203. {
    204. sprintf(loginfo, "(batchCount - ignoreCount)(%d) == rowsCount(%d)", (batchCount - ignoreCount), rowsCount);
    205. if (!SQL_SUCCEEDED(retcode)) {
    206. printf("SQLExecute failed");
    207. goto exit;
    208. }
    209. }
    210. // check row number returned
    211. if (rowsCount != process)
    212. {
    213. sprintf(loginfo, "process(%d) != rowsCount(%d)", process, rowsCount);
    214. if (!SQL_SUCCEEDED(retcode)) {
    215. printf("SQLExecute failed");
    216. goto exit;
    217. }
    218. }
    219. else
    220. {
    221. sprintf(loginfo, "process(%d) == rowsCount(%d)", process, rowsCount);
    222. if (!SQL_SUCCEEDED(retcode)) {
    223. printf("SQLExecute failed");
    224. goto exit;
    225. }
    226. }
    227. for (int i = 0; i < batchCount; i++)
    228. {
    229. if (i < ignoreCount)
    230. {
    231. if (statusptr[i] != SQL_PARAM_UNUSED)
    232. {
    233. sprintf(loginfo, "statusptr[%d](%d) != SQL_PARAM_UNUSED", i, statusptr[i]);
    234. if (!SQL_SUCCEEDED(retcode)) {
    235. printf("SQLExecute failed");
    236. goto exit;
    237. }
    238. }
    239. }
    240. else if (statusptr[i] != SQL_PARAM_SUCCESS)
    241. {
    242. sprintf(loginfo, "statusptr[%d](%d) != SQL_PARAM_SUCCESS", i, statusptr[i]);
    243. if (!SQL_SUCCEEDED(retcode)) {
    244. printf("SQLExecute failed");
    245. goto exit;
    246. }
    247. }
    248. }
    249. retcode = SQLFreeHandle(SQL_HANDLE_STMT, hstmtinesrt);
    250. sprintf((char*)loginfo, "SQLFreeHandle hstmtinesrt");
    251. if (!SQL_SUCCEEDED(retcode)) {
    252. printf("SQLFreeHandle failed");
    253. goto exit;
    254. }
    255. }
    256. exit:
    257. (void) printf ("\nComplete.\n");
    258. // Connection
    259. if (hdbc != SQL_NULL_HDBC) {
    260. SQLDisconnect(hdbc);
    261. SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
    262. }
    263. // Environment
    264. if (henv != SQL_NULL_HENV)
    265. SQLFreeHandle(SQL_HANDLE_ENV, henv);
    266. }