unixODBC編程(十)分片插入長數據
訪問www.tomcoding.com網站,學習Oracle內部數據結構,詳細文檔說明,下載Oracle的exp/imp,DUL,logminer,ASM工具的源代碼,學習高技術含量的內容。還有數據庫實時復制軟件下載。
遇到有LONG數據類型的表,要插入一條數據量很大的行,一次插入的緩沖區會不夠大,這時需要一部分一部分的插入LONG數據,這就用到了在執行語句時動態提供數據的機制。在ODBC中要動態提供數據需要幾個步驟。
1. 在綁定輸入參數時,要在SQLBindParameter()函數中指定數據長度時,使用SQL_LEN_DATA_AT_EXEC()宏得到數據長度,告訴應用程序數據在執行語句時才提供,使用的數據類型要用SQL_LONGVARCHAR或SQL_LONGBINARY。同時數據指針要提供一個數值,標記這個字段,為了區分多個動態插入的字段,這個數值在后面調用SQLParamData()函數時會返回,這樣應用程序就知道現在是哪個字段需要提供數據。
2. 執行SQLExecute()或SQLExecDirect()函數,因為語句中有動態字段,所以函數會返回SQL_NEED_DATA的返回值。
3. 調用SQLParamData()函數,返回標識字段的數值,這時就知道是為哪個字段插入數據。函數返回SQL_NEED_DATA,這時需要提供數據。
4. 循環調用SQLPutData()函數,為字段提供動態數據,直到插入的數據完畢。
5. 再次調用SQLParamData()函數,看看是否還有下一個動態插入的字段需要操作,函數返回SQL_NEED_DATA,說明需要為新字段提供數據,重復步驟4的操作。如果返回SQL_SUCCESS,說明沒有要提供數據的字段了,把上一個動態插入數據的系列操作結束。
舉一個例子,在test_long1表中插入LONG數據,字段叫summary,插入10000個字符。SQLBindParameter()函數的StrLen_or_IndPtr參數設置為SQL_LEN_DATA_AT_EXEC(10000),ParameterType設置為SQL_LONGVARCHAR,ParameterValuePtr設置為參數的編號,比如編號為3,那么函數設置如下。
len_ind3 = SQL_LEN_DATA_AT_EXEC(10000);
SQLBindParameter(stmth, 3, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_LONGVARCHAR, 10000, 0, (void *)3, 0, &len_ind3);
下面我們看一個實際的例子,在test_long1表中插入一條數據,綁定三個參數,后面兩個參數都使用動態提供數據,主要看看SQLParamData()函數和SQLPutData()函數的用法,以及如何動態提供數據。代碼如下。
#include "stdio.h" #include "stdlib.h" #include "string.h" #include "sql.h" #include "sqlext.h" #include "sqltypes.h" SQLHANDLE envh; /* env handle */ SQLHANDLE dbch; /* connect handle */ SQLHANDLE stmth; /* statement handle */ int main(int argc, char *argv[]){ int conn = 0; SQLRETURN rc; SQLLEN len_ind1; SQLLEN len_ind2; SQLLEN len_ind3; SQLLEN total_amt; SQLLEN once_amt; SQLINTEGER id; SQLPOINTER param_id; char dsn_str[32]; char usrname[32]; char passwd[32]; char sqltxt[512]; char data[4096]; if (argc < 3) { fprintf(stderr, "usage: %s dsn username password\n", argv[0]); return (-1); } strncpy(dsn_str, argv[1], 32); dsn_str[31] = '\0'; strncpy(usrname, argv[2], 32); usrname[31] = '\0'; strncpy(passwd, argv[3], 32); passwd[31] = '\0'; rc = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &envh); if (rc != SQL_SUCCESS) { fprintf(stderr, "Allocate environment handle error.\n"); return (-1); } rc = SQLSetEnvAttr(envh, SQL_ATTR_ODBC_VERSION, (void *)SQL_OV_ODBC3, 0); if (rc != SQL_SUCCESS) { fprintf(stderr, "Set ODBC version error.\n"); goto free_exit; } rc = SQLAllocHandle(SQL_HANDLE_DBC, envh, &dbch); if (rc != SQL_SUCCESS) { fprintf(stderr, "Allocate DB connection handle error.\n"); goto free_exit; } rc = SQLSetConnectAttr(dbch, SQL_ATTR_LOGIN_TIMEOUT, (SQLPOINTER)10, 0); if (rc != SQL_SUCCESS) { fprintf(stderr, "Set connection timeout value error.\n"); goto free_exit; } rc = SQLConnect(dbch, (SQLCHAR *)dsn_str, SQL_NTS, (SQLCHAR *)usrname, SQL_NTS, (SQLCHAR *)passwd, SQL_NTS); if (rc != SQL_SUCCESS) { fprintf(stderr, "Connect to DB error.\n"); goto free_exit; } conn = 1; fprintf(stdout, "connect DB ok ......\n"); rc = SQLAllocHandle(SQL_HANDLE_STMT, dbch, &stmth); if (rc != SQL_SUCCESS) { fprintf(stderr, "Allocate statment handle error.\n"); goto free_exit; } /* 插入一條數據,輸入三個參數,note和summary動態提供數據 */ sprintf(sqltxt, "insert into test_long1 (id, name, addr, note, summary) values (?, 'AAAAAAAA', 'BBBBBBBBBB', ?, ?)"); rc = SQLPrepare(stmth, (SQLCHAR *)sqltxt, SQL_NTS); if (rc != SQL_SUCCESS) { fprintf(stderr, "Prepare statment error.\n"); goto free_exit; } /* ID字段的插入值為10 */ id = 10; /* ID正常插入,在綁定時提供數值 * NOTE在執行時動態提供數據,長度為40,數據為40個'C'字符,一次提供完畢 * SUMMARY在執行是動態提供數據,長度為10000,數據為10000個'D'字符,分多次提供 * NOTE和SUMMARY字段使用SQL_LEN_DATA_AT_EXEC()宏計算長度 */ len_ind1 = 0; len_ind2 = SQL_LEN_DATA_AT_EXEC(40); len_ind3 = SQL_LEN_DATA_AT_EXEC(10000); /* 綁定變量id */ rc = SQLBindParameter(stmth, 1, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, 0, 0, &id, 0, &len_ind1); if (rc != SQL_SUCCESS) { fprintf(stderr, "Bind column 1 error.\n"); goto free_exit; } /* 參數類型為SQL_LONGVARCHAR,數據指針指向參數編號2 */ rc = SQLBindParameter(stmth, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_LONGVARCHAR, 2000, 0, (void *)2, 0, &len_ind2); if (rc != SQL_SUCCESS) { fprintf(stderr, "Bind column 2 error.\n"); goto free_exit; } /* 參數類型為SQL_LONGVARCHAR,數據指針指向參數編號3 */ rc = SQLBindParameter(stmth, 3, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_LONGVARCHAR, 10000, 0, (void *)3, 0, &len_ind3); if (rc != SQL_SUCCESS) { fprintf(stderr, "Bind column 3 error.\n"); goto free_exit; } /* 執行插入語句,這時函數返回SQL_NEED_DATA */ rc = SQLExecute(stmth); if ((rc != SQL_SUCCESS) && (rc != SQL_NEED_DATA)) { fprintf(stderr, "Execute statment error.\n"); goto free_exit; } /* 循環檢查動態提供數據的字段 */ while (1) { /* 調用SQLParamData()函數,parma_id返回綁定時指定的參數編號 */ rc = SQLParamData(stmth, ¶m_id); if ((rc == SQL_SUCCESS) || (rc == SQL_SUCCESS_WITH_INFO)) /* 返回SQL_SUCCESS說明所有動態提供數據的字段都操作完成了,退出循環 */ break; if (rc != SQL_NEED_DATA) { /* 這里如果返回值不為SQL_NEED_DATA說明函數調用出錯了 */ fprintf(stderr, "Call SQLParamData() error.\n"); goto free_exit; } if (param_id == (SQLPOINTER)2) { /* param_id等于2,說明要為第二個參數提供數據,提供40個'C'字符 */ memset(data, 'C', 40); data[40] = '\0'; len_ind2 = 40; /* 調用SQLPutData()函數,為參數2提供數據 */ rc = SQLPutData(stmth, (SQLPOINTER)data, len_ind2); if ((rc != SQL_SUCCESS) && (rc != SQL_SUCCESS_WITH_INFO)) { fprintf(stderr, "Call SQLPutData() error.\n"); goto free_exit; } } else if (param_id == (SQLPOINTER)3) { /* param_id等于3,說明要為第三個參數提供數據,提供10000個'D'字符 * 每次提供4000字符,分三次提供完畢 */ once_amt = 4000; total_amt = 10000; memset(data, 'D', 4000); data[4000] = '\0'; while (total_amt > once_amt) { /* 每次提供4000字符 */ rc = SQLPutData(stmth, (SQLPOINTER)data, once_amt); if ((rc != SQL_SUCCESS) && (rc != SQL_SUCCESS_WITH_INFO)) { fprintf(stderr, "Call SQLPutData() error.\n"); goto free_exit; } total_amt -= once_amt; } if (total_amt > 0) { /* 提供最后的2000字符 */ rc = SQLPutData(stmth, (SQLPOINTER)data, total_amt); if ((rc != SQL_SUCCESS) && (rc != SQL_SUCCESS_WITH_INFO)) { fprintf(stderr, "Call SQLPutData() error.\n"); goto free_exit; } } } else { fprintf(stderr, "Invalid parameter number.\n"); goto free_exit; } } /* 提交改變的數據 */ rc = SQLEndTran(SQL_HANDLE_DBC, dbch, SQL_COMMIT); if (rc != SQL_SUCCESS) { fprintf(stderr, "End Transaction error.\n"); goto free_exit; } fprintf(stdout, "Insert data successed ......\n"); SQLFreeHandle(SQL_HANDLE_STMT, stmth); SQLDisconnect(dbch); SQLFreeHandle(SQL_HANDLE_DBC, dbch); SQLFreeHandle(SQL_HANDLE_ENV, envh); return (0); free_exit: if (stmth != NULL) { SQLFreeHandle(SQL_HANDLE_STMT, stmth); } if (conn) { SQLDisconnect(dbch); } if (dbch != NULL) { SQLFreeHandle(SQL_HANDLE_DBC, dbch); } if (envh != NULL) { SQLFreeHandle(SQL_HANDLE_ENV, envh); } return (-1); }
訪問www.tomcoding.com網站,學習Oracle內部數據結構,詳細文檔說明,下載Oracle的exp/imp,DUL,logminer,ASM工具的源代碼,學習高技術含量的內容。

浙公網安備 33010602011771號