OCI編程基礎(chǔ)篇(七) 插入數(shù)據(jù)
訪問www.tomcoding.com網(wǎng)站,學(xué)習(xí)Oracle內(nèi)部數(shù)據(jù)結(jié)構(gòu),詳細(xì)文檔說明,下載Oracle的exp/imp,DUL,logminer,ASM工具的源代碼,學(xué)習(xí)高技術(shù)含量的內(nèi)容。
這一節(jié)我們來看看怎樣向數(shù)據(jù)庫表中插入一條數(shù)據(jù),插入數(shù)據(jù)也有下面幾個步驟。
1. 分配一個SQL語句句柄,OCIHandleAlloc()。
2. 準(zhǔn)備SQL語句,OCIStmtPrepare()。
3. 為SQL語句綁定要插入的數(shù)據(jù),OCIBindByPos()。
4. 執(zhí)行SQL語句,OCIStmtExecute()。
5. 提交數(shù)據(jù)庫改變,OCITransCommit()。
下面我們看一下新出現(xiàn)的OCI函數(shù)的原型和參數(shù)。
第一個函數(shù)是準(zhǔn)備SQL語句,原型如下。
sword OCIStmtPrepare ( OCIStmt *stmtp,
OCIError *errhp,
const OraText *stmt,
ub4 stmt_len,
ub4 language,
ub4 mode );
stmtp是一個輸入?yún)?shù),是第一步中OCIHandleAlloc()分配的SQL語句句柄。
errhp是一個輸入?yún)?shù),用于調(diào)用出錯時返回錯誤碼和錯誤信息文本。
stmt是一個輸入?yún)?shù),是要執(zhí)行的SQL語句的文本,必須是一個NULL結(jié)束的字符串。
stmt_len是一個輸入?yún)?shù),是SQL語句文本的長度,一定不能賦值為0。
language是一個輸入?yún)?shù),取值OCI_NTV_SYNTAX,本地分析SQL語法。
mode是一個輸入?yún)?shù),唯一取值為OCI_DEFAULT。
這里重點(diǎn)說一下SQL語句文本,這個文本是有特殊格式的,如果插入一個表的數(shù)據(jù)有三個字段,假設(shè)表名叫做tab1,那么文本格式為INSERT INTO tab1 VALUES (:1, :2, :3)。這里的1,2,3叫做占位符,后續(xù)要通過綁定函數(shù)把插入的值與占位符關(guān)聯(lián)起來。占位符也可以叫別的名字,只要前面是冒號開頭的都是占位符,用1,2,3來表示是為了與占位符的位置一致。
第二個函數(shù)是綁定數(shù)據(jù),原型如下。
sword OCIBindByPos ( OCIStmt *stmtp,
OCIBind **bindpp,
OCIError *errhp,
ub4 position,
void *valuep,
sb4 value_sz,
ub2 dty,
void *indp,
ub2 *alenp,
ub2 *rcodep,
ub4 maxarr_len,
ub4 *curelep,
ub4 mode );
stmtp是一個輸入?yún)?shù)/輸出參數(shù),是要處理的SQL語句句柄。
bindpp是一個輸入/輸出參數(shù),這時一個綁定句柄的指針,調(diào)用函數(shù)后,會隱式的分配一個句柄,這個參數(shù)把綁定句柄帶回,后續(xù)所有針對這個綁定值的操作都通過這個句柄進(jìn)行。綁定句柄在語句句柄釋放時也會隱式的釋放掉。如果不需要對綁定值進(jìn)行其他操作,可以賦值為NULL。
errhp是一個輸入/輸出參數(shù),用于函數(shù)調(diào)用出錯后獲取錯誤碼和錯誤信息文本。
position是一個輸入?yún)?shù),指定占位符的位置,從1開始計算位置。
valuep是一個輸入/輸出參數(shù),如果是一個宿主變量,輸入的就是這個變量的地址,如果是一個宿主變量數(shù)組,輸入的就是數(shù)組的地址。在一些PL/SQL塊中如果需要返回值,也是要用到綁定函數(shù)的,所以這個值也可以用作輸出參數(shù)。
value_sz是一個輸入?yún)?shù),是綁定數(shù)據(jù)的最大可能長度,比如你定義了一個100字符的數(shù)組,那么這個參數(shù)就賦值為100,不管實際的數(shù)據(jù)長度是多少。
dty是一個輸入?yún)?shù),指定數(shù)據(jù)類型。典型的整數(shù)為SQLT_INT,字符串為SQLT_STR 。
indp是一個輸入/輸出參數(shù),指向一個指示變量或指示變量數(shù)組,指示變量是一個sb2類型的16位整數(shù),如果綁定值是NULL,指示變量要設(shè)置為-1,否則設(shè)置為0。如果綁定的是一個輸出變量,指示變量也要設(shè)置為0。
alenp是一個輸入/輸出參數(shù),綁定數(shù)據(jù)的實際大小。指向一個ub2類型的整數(shù)或整數(shù)數(shù)組。
rcodep是一個輸出參數(shù),返回字段級的錯誤碼。指向一個ub2類型的整數(shù)或整數(shù)數(shù)組。
maxarr_len是一個輸入?yún)?shù),最大數(shù)組元素個數(shù),只用于PL/SQL中的索引表綁定。
curelep是一個輸入/輸出參數(shù),實際數(shù)組元素個數(shù),只用于PL/SQL中的索引表綁定。
mode是一個輸入?yún)?shù),指示綁定模式。一般取值為OCI_DEFAULT。
函數(shù)中的數(shù)據(jù)類型還有很多種,這里列一個表看看其他取值。
|
SQLT_CHR |
對應(yīng)VARCHAR2,在C語言中對應(yīng)一個字符數(shù)組char[n] |
|
SQLT_NUM |
對應(yīng)Oracle格式的NUMBER類型 |
|
SQLT_INT |
對應(yīng)64位及以下的有符號整數(shù) |
|
SQLT_UIN |
對應(yīng)64位及以下的無符合整數(shù) |
|
SQLT_STR |
對應(yīng)一個NULL結(jié)尾的字符串 |
|
SQLT_LNG |
對應(yīng)LONG類型 |
|
SQLT_DAT |
對應(yīng)Oracle格式的日期類型 |
|
SQLT_BFLOAT |
對應(yīng)BINARY_FLOAT類型 |
|
SQLT_BDOUBLE |
對應(yīng)BINARY_DOUBLE類型 |
|
SQLT_BIN |
對應(yīng)RAW類型 |
|
SQLT_LBI |
對應(yīng)LONG RAW類型 |
|
SQLT_AFC |
對應(yīng)CHAR類型 |
第三個函數(shù)是執(zhí)行語句,原型如下。
sword OCIStmtExecute ( OCISvcCtx *svchp,
OCIStmt *stmtp,
OCIError *errhp,
ub4 iters,
ub4 rowoff,
const OCISnapshot *snap_in,
OCISnapshot *snap_out,
ub4 mode );
svchp是一個輸入/輸出參數(shù),是連接數(shù)據(jù)庫時分配的服務(wù)上下文句柄。
stmtp是一個輸入/輸出參數(shù),SQL語句句柄。
errhp是一個輸入/輸出參數(shù),用于獲取錯誤碼和錯誤信息文本。
iters是一個輸入?yún)?shù),對于更新數(shù)據(jù)庫的操作和查詢數(shù)據(jù)庫的操作,含義是不一樣的。對于更新數(shù)據(jù)庫操作,這是迭代次數(shù),SQL語句要執(zhí)行iters-rowoff次。對于查詢操作一般設(shè)置這個參數(shù)為0,如果不為0,表示執(zhí)行語句后,預(yù)先獲取的數(shù)據(jù)條數(shù)。
rowoff是一個輸入?yún)?shù),對于數(shù)組操作,指示從哪條數(shù)據(jù)開始處理。第一條從0開始計算。
snap_in是一個輸入?yún)?shù),對于查詢操作,輸入一個快照句柄,為了幾個不同的查詢用同一個快照取得相同時間點(diǎn)的數(shù)據(jù)。對更新數(shù)據(jù)庫操作,這個參數(shù)會被忽略。一般賦值為NULL即可。
snap_out是一個輸出參數(shù),對于查詢操作,輸出一個當(dāng)前SCN時間點(diǎn)的快照。對更新數(shù)據(jù)庫操作,這個參數(shù)會被忽略。一般賦值為NULL即可。
mode是一個輸入?yún)?shù),一般取值為OCI_DEFAULT。
第四個函數(shù)是提交改變,原型如下。
sword OCITransCommit ( OCISvcCtx *svchp,
OCIError *errhp,
ub4 flags );
svchp是一個輸入?yún)?shù),服務(wù)上下文句柄。
errhp是一個輸入?yún)?shù),錯誤句柄,獲取出錯的錯誤碼和錯誤信息文本。
flags是一個輸入?yún)?shù),一般取值為OCI_DEFAULT。
舉一個例子,創(chuàng)建一個表,然后向表中插入一條數(shù)據(jù),在sqlplus中操作如下。
CREATE TABLE test_tab (ID NUMBER, NAME CHAR(30), ADDR VARCHAR2(200));
INSERT INTO test_tab VALUES (1, 'aaaaaaaa', 'bbbbbbbbbbbbbbbbbbbb');
COMMIT;
下面我們用OCI程序插入,源代碼如下。
OCIEnv *envhp = NULL;
OCIError *errhp = NULL;
OCIServer *svrhp = NULL;
OCISession *usrhp = NULL;
OCISvcCtx *svchp = NULL;
OCIStmt *smthp = NULL;
/* 插入一條數(shù)據(jù) */
int insert_one_row(void){
sword rc;
int slen;
sb2 ind_id;
sb2 ind_name;
sb2 ind_addr;
ub2 alen_id;
ub2 alen_name;
ub2 alen_addr;
ub2 rcode_id;
ub2 rcode_name;
ub2 rcode_addr;
int32_t id;
char name[32];
char addr[256];
OCIBind *bndp;
char sqltxt[1024];
/* 分配OCI語句句柄 */
rc = OCIHandleAlloc(
(void *)envhp,
(void **)&smthp,
OCI_HTYPE_STMT,
0,
(void **)NULL
);
if (rc != OCI_SUCCESS) {
fprintf(stderr, "OCIHandleAlloc() - allocate statement handle error !\n");
return (-1);
}
/* 生成SQL語句文本 */
strcpy(sqltxt, "INSERT INTO test_tab (ID, NAME, ADDR) VALUES (:1, :2, :3)");
slen = strlen(sqltxt);
/* 準(zhǔn)備語句 */
if (check_oci_error(errhp,
OCIStmtPrepare(smthp, errhp, (const OraText *)sqltxt, slen,
OCI_NTV_SYNTAX, OCI_DEFAULT)) < 0)
return (-1);
/* 綁定第一個占位符ID */
if (check_oci_error(errhp,
OCIBindByPos((OCIStmt *)smthp,
(OCIBind **)&bndp,
errhp,
(ub4)1, /* position */
(void *)&id, /* valuep */
(sb4)4, /* value_sz */
(ub2)SQLT_INT, /* dty */
(void *)&ind_id, /* indp */
(ub2 *)&alen_id, /* alenp */
(ub2 *)&rcode_id, /* column return code pointer */
(ub4)0, /* maxarr_len */
(ub4 *)NULL, /* curelep */
(ub4)OCI_DEFAULT) /* mode */
) < 0)
return (-1);
/* 綁定第二個占位符NAME */
if (check_oci_error(errhp,
OCIBindByPos((OCIStmt *)smthp,
(OCIBind **)&bndp,
errhp,
(ub4)2, /* position */
(void *)name, /* valuep */
(sb4)30, /* value_sz */
(ub2)SQLT_STR, /* dty */
(void *)&ind_name, /* indp */
(ub2 *)&alen_name, /* alenp */
(ub2 *)&rcode_name, /* column return code pointer */
(ub4)0, /* maxarr_len */
(ub4 *)NULL, /* curelep */
(ub4)OCI_DEFAULT) /* mode */
) < 0)
return (-1);
/* 綁定第三個占位符ADDR */
if (check_oci_error(errhp,
OCIBindByPos((OCIStmt *)smthp,
(OCIBind **)&bndp,
errhp,
(ub4)3, /* position */
(void *)addr, /* valuep */
(sb4)200, /* value_sz */
(ub2)SQLT_STR, /* dty */
(void *)&ind_addr, /* indp */
(ub2 *)&alen_addr, /* alenp */
(ub2 *)&rcode_addr, /* column return code pointer */
(ub4)0, /* maxarr_len */
(ub4 *)NULL, /* curelep */
(ub4)OCI_DEFAULT) /* mode */
) < 0)
return (-1);
/* 賦值綁定的變量數(shù)據(jù) */
id = 1;
strcpy(name, "aaaaaaaa");
strcpy(addr, "bbbbbbbbbbbbbbbbbbbb");
/* 指示符賦值為0,插入非NULL數(shù)據(jù) */
ind_id = 0;
ind_name = 0;
ind_addr = 0;
/* 賦值變量的真實數(shù)據(jù)長度 */
alen_id = 4;
alen_name = strlen(name) + 1;
alen_addr = strlen(addr) + 1;
/* 執(zhí)行OCI語句 */
if (check_oci_error(errhp,
OCIStmtExecute(svchp,
smthp, /* stmthp */
errhp, /* errhp */
1, /* iters */
0, /* rowoff */
NULL, /* snap_in */
NULL, /* snap_out */
OCI_DEFAULT) /* mode */
) < 0)
return (-1);
/* 提交改變的數(shù)據(jù) */
if (check_oci_error(errhp,
OCITransCommit(svchp, errhp, OCI_DEFAULT)) < 0)
return (-1);
return (0);
}
上面的程序中我們使用了前面編寫的錯誤處理函數(shù)check_oci_error(),簡化代碼,便利閱讀。如果在上面的例子中插入第二條數(shù)據(jù),不需要重新綁定,只需要在執(zhí)行語句前把變量的值改變,然后執(zhí)行語句就能插入數(shù)據(jù)。

浙公網(wǎng)安備 33010602011771號