OCI編程高級篇(七) LOB綁定和定義
訪問www.tomcoding.com網站,學習Oracle內部數據結構,詳細文檔說明,下載Oracle的exp/imp,DUL,logminer,ASM工具的源代碼,學習高技術含量的內容。
要插入LOB字段數據有多種辦法,其中一種就是把LOB數據當做普通數據來處理,直接綁定變量,變量指向LOB數據,然后執(zhí)行語句,就能插入數據。這時CLOB要用VARCHAR2類型綁定,BLOB用RAW類型綁定。這種方式適合插入小數據量的LOB數據,如果要插入大量的LOB數據(一般超過4000字節(jié)),就需要綁定LOB定位符,然后插入一個空的LOB定位符,隨后通過LOB SELECT操作得到這個LOB的完整定位符信息,通過LOB的寫函數,分批寫入LOB數據。
先看看LOB定位符的綁定,使用OCIBindByPos()函數,綁定值是LOB定位符的指針,大小為定位符指針的大小sizeof(OCILobLocator *),其他參數與綁定別的字段類型相同。如果是綁定CLOB,操作如下。
OCILobLocator *locp; OCIBindByPos((smthp, (OCIBind **)&bndp, errhp, (ub4)1, (void *)&locp, (sb4)sizeof(OCILobLocator *), (ub2)SQLT_CLOB, (void *)NULL, /* indicator */ (ub2 *)NULL, /* alenp */ (ub2 *)NULL, /* column return code pointer */ (ub4)0, /* maxarr_len */ (ub4 *)NULL, /* curelep */ (ub4)OCI_DEFAULT);
執(zhí)行LOB SELECT操作就要進行變量輸出定義,用到OCIDefineByPos()函數,還以定義CLOB為例,操作如下。
OCILobLocator *locp; OCIDefineByPos(smthp, (OCIDefine **)&defp, errhp, (ub4)1, (void *)&locp, (sb4)sizeof(OCILobLocator *), (ub2)SQLT_CLOB, (void *)NULL, (ub2 *)NULL, (ub2 *)NULL, (ub4)OCI_DEFAULT);
注意在綁定和定義函數中LOB定位符輸入的都是定位符的地址,是一個指針的指針,千萬不要用錯了。
我們舉一個例子,創(chuàng)建一個CLOB表叫做test_clob_tab,創(chuàng)建語句為CREATE TABLE test_clob_tab (ID NUMBER, MESSAGE CLOB)。然后向表中插入一條數據INSERT INTO test_clob_tab values (1, EMPTY_CLOB()),然后通過SELECT MESSAGE FROM test_clob_tab WHERE ID=1查詢語句得到LOB的定位符。我們寫一段程序通過OCI來實現上面的操作,這也是為后面向LOB字段中寫入LOB數據做準備。
OCIEnv *envhp = NULL; OCIError *errhp = NULL; OCIServer *svrhp = NULL; OCISession *usrhp = NULL; OCISvcCtx *svchp = NULL; OCIStmt *smthp = NULL; ??int insert_one_lob(void){ sword rc; sb4 ec; int slen; sb2 ind_msg; ub2 alen_msg; ub4 lob_empty = 0; OCIBind *bndp; OCIDefine *defp; OCILobLocator *locp; char sqltxt[1024]; text errbuf[512]; strcpy(sqltxt, "INSERT INTO test_clob_tab (ID, MESSAGE) values (1, :1)"); slen = strlen(sqltxt); rc = OCIStmtPrepare(smthp, errhp, (const OraText *)sqltxt, slen, OCI_NTV_SYNTAX, OCI_DEFAULT); if (rc != OCI_SUCCESS) { OCIErrorGet(errhp, 1, NULL, &ec, errbuf, 512, OCI_HTYPE_ERROR); fprintf(stderr, "OCIStmtPrepare() - [%d] %s\n", ec, errbuf); return (-1); } /* 分配LOB定位符 */ rc = OCIDescriptorAlloc((const void *)envhp, (void **)&locp, OCI_DTYPE_LOB, 0, (void **)NULL); if (rc != OCI_SUCCESS) { OCIErrorGet(envhp, 1, NULL, &ec, errbuf, 512, OCI_HTYPE_ERROR); fprintf(stderr, "OCIDescriptorAlloc() - [%d] %s\n", ec, errbuf); return (-1); } /* 設置為空LOB */ rc = OCIAttrSet((void *)(*locp), (ub4)OCI_DTYPE_LOB, (void *)&lob_empty, (ub4)0, (ub4)OCI_ATTR_LOBEMPTY, errhp); if (rc != OCI_SUCCESS) { OCIErrorGet(envhp, 1, NULL, &ec, errbuf, 512, OCI_HTYPE_ERROR); fprintf(stderr, "OCIAttrSet() - [%d] %s\n", ec, errbuf); return (-1); } /* 綁定LOB定位符 */ rc = OCIBindByPos((OCIStmt *)smthp, (OCIBind **)&bndp, errhp, (ub4)1, (void *)&locp, (sb4)sizeof(OCILobLocator *), (ub2)SQLT_CLOB, (void *)&ind_msg, /* indp */ (ub2 *)&alen_msg, /* alenp */ (ub2 *)NULL, /* column return code pointer */ (ub4)0, /* maxarr_len */ (ub4 *)NULL, /* curelep */ (ub4)OCI_DEFAULT); /* mode */ if (rc != OCI_SUCCESS) { OCIErrorGet(errhp, 1, NULL, &ec, errbuf, 512, OCI_HTYPE_ERROR); fprintf(stderr, "OCIBindByPos() - [%d] %s\n", ec, errbuf); return (-1); } ind_msg = 0; alen_msg = sizeof(OCILobLocator *); /* 執(zhí)行語句 */ rc = OCIStmtExecute(svchp, smthp, /* stmthp */ errhp, /* errhp */ 1, /* iters */ 0, /* rowoff */ NULL, /* snap_in */ NULL, /* snap_out */ OCI_DEFAULT); /* mode */ if (rc != OCI_SUCCESS) { OCIErrorGet(errhp, 1, NULL, &ec, errbuf, 512, OCI_HTYPE_ERROR); fprintf(stderr, "OCIExecute() - [%d] %s\n", ec, errbuf); return (-1); } /* 提交改變 */ rc = OCITransCommit(svchp, errhp, OCI_DEFAULT); if (rc != OCI_SUCCESS) { OCIErrorGet(errhp, 1, NULL, &ec, errbuf, 512, OCI_HTYPE_ERROR); fprintf(stderr, "OCITransCommit() - [%d] %s\n", ec, errbuf); return (-1); } /* 下面執(zhí)行LOB SELECT操作 */ strcpy(sqltxt, "SELECT MESSAGE FROM test_clob_tab WHERE ID=1"); slen = strlen(sqltxt); rc = OCIStmtPrepare(smthp, errhp, (const OraText *)sqltxt, slen, OCI_NTV_SYNTAX, OCI_DEFAULT); if (rc != OCI_SUCCESS) { OCIErrorGet(errhp, 1, NULL, &ec, errbuf, 512, OCI_HTYPE_ERROR); fprintf(stderr, "OCIStmtPrepare() - [%d] %s\n", ec, errbuf); return (-1); } /* 定義LOB定位符輸出 */ rc = OCIDefineByPos((OCIStmt *)smthp, (OCIDefine **)&defp, (OCIError *)errhp, (ub4)1, (void *)&locp, (sb4)sizeof(OCILobLocator *), (ub2)SQLT_CLOB, (void *)&ind_msg, (ub2 *)&alen_msg, (ub2 *)NULL, /* column return code pointer */ (ub4)OCI_DEFAULT); if (rc != OCI_SUCCESS) { OCIErrorGet(errhp, 1, NULL, &ec, errbuf, 512, OCI_HTYPE_ERROR); fprintf(stderr, "OCIDefineByPos() - [%d] %s\n", ec, errbuf); return (-1); } /* 執(zhí)行語句 */ rc = OCIStmtExecute(svchp, smthp, /* stmthp */ errhp, /* errhp */ 0, /* iters */ 0, /* rowoff */ NULL, /* snap_in */ NULL, /* snap_out */ OCI_DEFAULT); /* mode */ if (rc != OCI_SUCCESS) { OCIErrorGet(errhp, 1, NULL, &ec, errbuf, 512, OCI_HTYPE_ERROR); fprintf(stderr, "OCIExecute() - [%d] %s\n", ec, errbuf); return (-1); } /* 執(zhí)行fetch操作 */ rc = OCIStmtFetch(smthp, errhp, 1, OCI_FETCH_NEXT, OCI_DEFAULT); if (rc != OCI_SUCCESS) { OCIErrorGet(errhp, 1, NULL, &ec, errbuf, 512, OCI_HTYPE_ERROR); fprintf(stderr, "OCIStmtFetch() - [%d] %s\n", ec, errbuf); return (-1); } /* 至此,ID=1的記錄中的LOB字段的LOB定位符就存儲在了locp指針中了 * 后面,就可以通過這個定位符寫入數據了 * 從上面的代碼也看到,要寫入LOB數據,之前的操作很繁瑣 */ /* 釋放LOB定位符 */ rc = OCIDescriptorFree((void *)locp, OCI_DTYPE_LOB); if (rc != OCI_SUCCESS) { OCIErrorGet(errhp, 1, NULL, &ec, errbuf, 512, OCI_HTYPE_ERROR); fprintf(stderr, "OCIDescriptorFree() - [%d] %s\n", ec, errbuf); return (-1); } return (0); }
從上面的代碼看到在插入空LOB到寫入LOB數據之前,要經過很繁瑣的操作,當你真正寫一段能跑起來的代碼不能說象噩夢,至少也夠頭疼的,有沒有辦法把這個過程變得簡潔一些,省去這些繁瑣的代碼呢?OCI提供了你想要的一切功能,只要你能想到好的辦法,編程永遠是思想比代碼重要,后面我們會介紹一種節(jié)約代碼的方法。

浙公網安備 33010602011771號