PROC++批次匯入匯出ORACLE資料庫表 (轉)
最近在開發一個專案中,為了解決IO瓶頸,不得不把資料庫中的資料匯出為文字。文字傳到客戶端後又要匯入到資料庫。本人用C++Builder嵌入PROC++寫了一個匯入匯出的DLL。如果對你有用深感榮幸!詳細內容如下:
一、準備工作
環境:Win 2000 PRO, 9i,C++ Builder 5.5
引入必要的ORACLE內部:要用的函式在$(ORACEL_HOME)inora9.dll連結庫中。為了能在C++ Builder中使用,先得生成LIB:implib sqlora9.lib sqlora9.dll
二、原始檔分析
//-------------------------------------------------------------------------
//加入必要的標頭檔案
#include
#include
//說明DLL的輸出函式
extern "C" _declspec(dllexport) int _stdcall Connect(const char *Username,
const char *Pass, const char *Dbname);
extern "C" _declspec(dllexport) int _stdcall ImportTxtfile(TList *LengthArray,
String *FieldArray, const char *TableName,
const char *FileName);
extern "C" _declspec(dllexport) int _stdcall ExportTxtfile(const char *Sql,
const char *FileName);
#pragma hdrstop
//----------------------------------------------------------------------------
#define MAX_ITEMS 20 //定義最大欄位數
#define MAX_VNAME_LEN 30 //定義選擇表項最大長度
#define MAX_INAME_LEN 30 //定義指示器變數名字的最大長度
:namespace prefix = o ns = "urn:schemas--com::office" />
EXEC SQL INCLUDE sqlca; //說明SQL通訊區
EXEC SQL INCLUDE oraca; //說明ORACLE通訊區
EXEC SQL INCLUDE sqlda; //說明SQL語句描述結構/*SQLDA結構體請查相關資料*/
EXEC ORACLE OPTION (ORACA = YES);
EXEC ORACLE OPTION (RELEASE_CURSOR = YES);
//說明ORACLE外部函式
extern "C" _declspec(dllimport) void _stdcall sqlclu(SQLDA*);
extern "C" _declspec(dllimport) void _stdcall sqlnul(short*, short*, int*);
extern "C" _declspec(dllimport) void _stdcall sqlprc(int*, int*, int*);
extern "C" _declspec(dllimport) struct SQLDA * _stdcall sqlald(int, unsigned int, unsigned int);
SQLDA *Unit; //定義選擇項描述
SQLDA *BindUnit; //定義輸入項空間
//定義變數,以存放連線資料庫的引數
EXEC SQL BEGIN DECLARE SECTION;
char User[20];//名
char Pwd[20];//密碼
char DB[20];//資料庫服務名
EXEC SQL END DECLARE SECTION;
bool bConnect = false;//是否連線標誌
#pragma hdrstop
#pragma argsused
//C++ Builder DLL的主函式
BOOL WIN DllMain(HINSTANCE hinstDLL, DWORD fwdreason, LPVOID lpvReserved)
{
return 1;
}
/*---------------------------------------------------------------------------
連線資料庫
---------------------------------------------------------------------------*/
int _stdcall ConnectDB(const char *Username, const char *Password,
const char *Dbname)
{
strcpy(User, Username);
strcpy(Pwd, Password);
strcpy(DB, Dbname);
EXEC SQL CONNECT :User NTIFIED BY :Pwd USING :DB;
if (sqlca.sqlcode < 0)
return -1;
bConnect = true;
return 0;
}
/*---------------------------------------------------------------------------
匯出文字函式
因為不確定SELECT語句的表及欄位,所以我使用動態語句(ORACLE DYNAMIC SQL)的//第四種方式。動態SQL方法四是在不確定SQL語句的選擇項與輸入項,且不知個數與資料型別的情況下使用的一種複雜設計技術。
---------------------------------------------------------------------------*/
int _stdcall ExportTxtfile(const char *Sql/*SQL選擇語句*/, const char FileName/*匯出目標文字檔名*/)
{
int null_ok, precision, scale;
int handle;
if ((handle = open(FileName, O_CREAT|O_TEXT|O_APPEND|O_RDWR, S_IREAD|S_IWRITE)) == -1)
{
//檔案開啟出錯
return -1;
}
//定義變數,以存放SQL語句
EXEC SQL BEGIN DECLARE SECTION;
char sqlstr[256];
EXEC SQL END DECLARE SECTION;
//檢查是否連線資料庫
if (bConnect == false) return -2;
strcpy(sqlstr/*.arr*/, Sql);
// sqlstr.len = strlen(sql);
//給描述區分配空間
if ((SelectUnit = sqlald(MAX_ITEMS, MAX_VNAME_LEN, MAX_INAME_LEN)) == (SQLDA *)NULL)
{
//空間分配失敗
return -3;
}
if ((BindUnit = sqlald(MAX_ITEMS, MAX_VNAME_LEN, MAX_INAME_LEN)) == (SQLDA *)NULL)
{
//空間分配失敗
return -3;
}
//給查詢返回值區分配空間
SelectUnit->N = MAX_ITEMS;
for (int i=0; i < MAX_ITEMS; i++)
{
BindUnit->I[i] = (short *)malloc(sizeof(short *));
BindUnit->V[i] = (char *)malloc(MAX_VNAME_LEN);
}
for (int i=0; i < MAX_ITEMS; i++)
{
SelectUnit->I[i] = (short *)malloc(sizeof(short *));
SelectUnit->V[i] = (char *)malloc(MAX_VNAME_LEN);
}
EXEC SQL WHENEVER SQLERROR GOTO sqlerr;//DO sql_error("匯出出錯");
//設定SQL語句
EXEC SQL PREPARE SQLSA FROM :sqlstr;
EXEC SQL DECLARE Cursorbase CURSOR FOR SQLSA;
//輸入描述處理
BindUnit->N = MAX_ITEMS;
EXEC SQL DESCRIBE BIND VARIABLES for SQLSA INTO BindUnit;
if (BindUnit->F < 0)
{
return -4;
//輸入項過多
}
BindUnit->N = BindUnit->F;
//開啟游標
EXEC SQL OPEN Cursorbase USING DESCRIPTOR BindUnit;
//選擇項處理
EXEC SQL DESCRIBE SELECT LIST for SQLSA INTO SelectUnit;
if (SelectUnit->F < 0)
{
return -4;
//選擇表項過多
}
SelectUnit->N = SelectUnit->F;
//因為所有格式,型別都是不確定的,所以要得到正確的返回值就要處理格式
for (int i=0; i < SelectUnit->F; i++)
{
sqlnul(&(SelectUnit->T[i]), &(SelectUnit->T[i]), &null_ok);
switch (SelectUnit->T[i])
{
case 1://CHAR
break;
case 2://NUMBER
sqlprc(&(SelectUnit->L[i]), &precision, &scale);
if (precision == 0)
precision = 40;
SelectUnit->L[i] = precision + 2;
break;
case 8://LONG
SelectUnit->L[i] = 240;
break;
case 11://ROWID
SelectUnit->L[i] = 18;
break;
case 12://DATE
SelectUnit->L[i] = 9;
break;
case 23://RAW
break;
case 24://LONGRAW
SelectUnit->L[i] = 240;
break;
}
SelectUnit->V[i] = (char *)realloc(SelectUnit->V[i], SelectUnit->L[i]+1);
SelectUnit->T[i] = 1;//把所有型別轉換為字元型
}
EXEC SQL WHENEVER NOT FOUND goto EndFor;
for (;;)
{
EXEC SQL FETCH Cursorbase USING DESCRIPTOR SelectUnit;
//輸出各欄位
for (int i=0; i < SelectUnit->F; i++)
{
char buffer[256];
if (i != SelectUnit->F-1)
sprintf(buffer, "%s", SelectUnit->V[i]);
else sprintf(buffer, "%s ", SelectUnit->V[i]);
int length = strlen(buffer);
if (write(handle, buffer, length) != length)
{
return -5;
//寫檔案失敗 exit(1);
}
}
}
EndFor:
close(handle);
for (int i=0; i < MAX_ITEMS; i++)
{
if (SelectUnit->V[i] != (char *)NULL)
free(SelectUnit->V[i]);
free(SelectUnit->I[i]);
}
for (int j=0; j < MAX_ITEMS; j++)
{
if (BindUnit->V[j] != (char *)NULL)
free(BindUnit->V[j]);
free(BindUnit->I[j]);
}
sqlclu(SelectUnit);
sqlclu(BindUnit);
EXEC SQL CLOSE Cursorbase;
return 0;
sqlerr:
return -6;
}
/*----------------------------------------------------------------------------
匯入文字
為了批次匯入,在此我的sqlldr工具
首先生成SQL*Loader控制檔案,後執行sqlldr
----------------------------------------------------------------------------*/
int _stdcall ImportTxtfile(TList LengthArray/*匯入文字的欄位長度連結串列*/,
String *FieldArray/*資料庫表的了段名陣列*/, const char TableName/*匯入的目標表*/, const char FileName/*匯入的源文字檔案*/)
{
//產生SQL*Loader控制檔案
FILE *fout, *fp;
char Execommand[256];
char sqlload[] = ".sqlload.ctl";
//檢查是否連線資料庫
if (bConnect == false) return -2;
if ((fout=fopen(sqlload, "w")) == NULL)
{
//建立控制檔案出錯
return -1 ;
}
fprintf(fout, "LOAD DATA ");
fprintf(fout, "INFILE '%s' ", FileName);
fprintf(fout, "APPEND INTO TABLE %s ( ", TableName);
int iStart = 1;
for(int i=0; i < LengthArray->Count; i++)
{
fprintf(fout, "%11s POSITION(%d:%d)", FieldArray[i], iStart, *(int*)LengthArray->Items[i]+iStart-1);
iStart += *(int*)LengthArray->Items[i];
fprintf(fout, " CHAR");
if(i < LengthArray->Count-1)
fprintf(fout, ", ");
}
fprintf(fout, ") ");
fclose(fout);
sprintf(Execommand, "sqlldr.exe userid=%s/%s@%s control=%s",
User, Pwd, DB, sqlload);
if (system(Execommand) == -1)
{
//SQL*Loader錯誤
return -1;
}
return 0 ;
}
//----------------------------------------------------------------------------
三、編譯
用ORACLE的PROC預預編後,放入C++ Builder中聯編。聯編時需加入前面生成的sqlora9.lib。聯編時還要注意,所有PROC生成的ORACLE內部函式呼叫都要說明為extern "C" _declspec(dllexport) TYPE _stdcall型別。
水平有限還請見諒!!!請多多指點。QQ:5005647
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752019/viewspace-959143/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Oracle資料庫匯入匯出。imp匯入命令和exp匯出命令Oracle資料庫
- Oracle 資料匯入匯出Oracle
- Oracle資料匯入匯出Oracle
- oracle資料匯出匯入(exp/imp)Oracle
- 資料庫 MySQL 資料匯入匯出資料庫MySql
- OracleDatabase——資料庫表空間dmp匯出與匯入OracleDatabase資料庫
- Oracle資料泵匯出匯入(expdp/impdp)Oracle
- Oracle資料泵的匯入和匯出Oracle
- Mysql 資料庫匯入與匯出MySql資料庫
- Access 匯入 oracle 資料庫Oracle資料庫
- SpringBoot+Mybatis-plus整合easyExcel批次匯入Excel到資料庫+匯出ExcelSpring BootMyBatisExcel資料庫
- ClickHouse 資料表匯出和匯入(qbit)
- SQL資料庫的匯入和匯出SQL資料庫
- 達夢資料庫遷移資料/複製表/匯入匯出2資料庫
- oracle 備份資料庫,匯出資料庫Oracle資料庫
- Oracle使用資料泵expdp,impdp進行資料匯出匯入Oracle
- 小程式批次匯入excel資料,雲開發資料庫匯出cvs亂碼解決方案Excel資料庫
- 伺服器批次匯入與匯出伺服器
- Oracle匯出資料庫與還原Oracle資料庫
- sqoop資料匯入匯出OOP
- 資料泵匯出匯入
- phpMyAdmin匯入/匯出資料PHP
- [Docker核心之容器、資料庫檔案的匯入匯出、容器映象的匯入匯出]Docker資料庫
- fdw批次匯入外部表
- Oracle 12c expdp和impdp匯出匯入表Oracle
- Oracle資料庫——資料匯出時出現匯出成功終止, 但出現警告。Oracle資料庫
- mysqldump匯出匯入所有庫、某些庫、某些表的例子MySql
- Oracle 資料匯入ExcelOracleExcel
- 【oracle 多種形式的外部表匯入、匯出】實驗Oracle
- 【oracle 資料匯入匯出字元問題】Oracle字元
- [資料庫] Navicat for Oracle基本用法(匯入匯出正刪改查)圖文介紹資料庫Oracle
- MySQL入門--匯出和匯入資料MySql
- 大文字資料,匯入匯出到資料庫資料庫
- Mongodb資料的匯出與匯入MongoDB
- 匯入和匯出AWR的資料
- EasyPoi, Excel資料的匯入匯出Excel
- Excel 表匯入資料Excel
- AWR跨庫匯出與匯入
- 一次運維-堡壘機多次跳轉匯出及匯入mysql資料庫運維MySql資料庫