/*
* File: main.cpp
* Author: zengfankun@小凡仙
*
* Created on 2019年12月4日, 下午4:11
*/
#include
#include
#include
#include
#include
#include
using namespace std;
using namespace oracle::occi;
struct stc_dbconf //定义配置文件结构体
{
string dbname;
string classA;
string classB;
string classC;
string User;
string Password;
string Connect;
};
struct stc_dbFilter //定义过滤条件结构体
{
string m_s_classA;
string m_s_classB;
string m_s_classC;
string m_s_dbname;
};
struct stc_sqlconf //定义SQL配置结构体
{
string sqlid;
string sqltype;
string sqltext;
};
void Load_DbConf(vector &dblist);//装入DB配置文件
void Load_SqlConf(vector &sqlList);//装入SQL配置文件
//对配置列表过滤
void Filter_DbList(vector &Filter_dblist,stc_dbFilter stc_Filter);
void Filter_SqlList(vector &sqlList,string psql_id);//对SQL列表过滤
//连接数据库并执行SQL
void ConnDb_ExecQuery(vector &dblist,vector &sqlList);
int main(int argc, char** argv) //sqlid classA classB classC dbname
{ //参数列表 不输入用“NULLL" 占位
vector dbconf_List; //DB配置文件列表
vector Filted_dblist; //过滤后的DB配置文件列表
vector sqlList; //SQL配置文件列表
stc_dbFilter lstc_dbFilter; //过滤条件结构体变量
string m_s_sqlid; //SQLID变量
string m_s_argv;
cout<
cout<
cout<
for (int i=1;i
{
cout<
}
cout<
cout<
cout<
if(argc<=0){ cout<
if (argc>=2) //参数必须大于等于2个
{
m_s_sqlid =argv[1]; //参数赋值给变量
m_s_argv=argv[2];
if(m_s_argv=="NULL")
{
lstc_dbFilter.m_s_classA.clear(); //如果参数使用NULL占位,那么过滤变量置空
}
else
{
lstc_dbFilter.m_s_classA=argv[2];
}
m_s_argv=argv[3];
if(m_s_argv=="NULL")
{
lstc_dbFilter.m_s_classB.clear();
}
else
{
lstc_dbFilter.m_s_classB=argv[3];
}
m_s_argv=argv[4];
if(m_s_argv=="NULL")
{
lstc_dbFilter.m_s_classC.clear();
}
else
{
lstc_dbFilter.m_s_classC=argv[4];
}
m_s_argv=argv[5];
if(m_s_argv=="NULL")
{
lstc_dbFilter.m_s_dbname.clear();
}
else
{
lstc_dbFilter.m_s_dbname=argv[5];
}
m_s_argv="";
}
else { cout<
Load_DbConf(dbconf_List); //装入配置文件,把列表地址传进去添加数据
if (dbconf_List.size()<=0)
{
cout<
exit(1);
}
// for (int i=0;i
// { //尽在测试使用
// cout<
// cout<
// cout<
// cout<
// cout<
// cout<
// cout<
// cout<
// cout<
// }
Filted_dblist=dbconf_List; //保存配置文件列表,赋值给过滤后配置列表
Filter_DbList(Filted_dblist,lstc_dbFilter); //把过滤后配置列表和过滤变量传给函数处理
if(Filted_dblist.size()>0)
{
cout<
cout<
<
cout<
for (int j=0; j
{
cout<
<
<
<
<
<
cout<
cout<
}
}
else
{
cout<
exit(1);
}
Load_SqlConf(sqlList); //装入SQL配置文件到列表中
if(sqlList.size()<=0)
{
cout<
exit(1);
}
// for (int K=0; K
// {
// cout<
// cout<
// cout<
// cout<
// cout<
// cout<
// }
Filter_SqlList(sqlList,m_s_sqlid); //这里把没有必要的SQL过滤掉
if (sqlList.size()<=0)
{
cout<
exit(1);
}
for (int z=0;z
{
cout<
cout<
cout<
cout<
cout<
cout<
}
ConnDb_ExecQuery(Filted_dblist,sqlList);//正式去连数据库,并且执行指定的SQL
return 0;
}
void Load_DbConf(vector &dblist)
{
char linebuf[1024]; //读入文件1行的字符数组
int position=0; //确定等号的位置
int linebuf_size=0; //实际读入字符串大小
stc_dbconf lv_dbconf; //定义一个本地配置信息结构体变量
string key; //定义KEY变量
string value; //定义VALUE变量
string tmp_line; //定义行的字符串变量,方便操作
ifstream db_config_file; //文件操作的变量
db_config_file.open("db.conf",ios::in);//只读模式并在程序当前目录下打开文件
if(db_config_file==NULL) //判断文件是否打开成功
{
cout<
exit(1);
}
while(!db_config_file.eof()) //读取每一行,在文件结束前
{
db_config_file.getline(linebuf,1024); //读入一行,放入1024个字符数组中
//判断几个特殊字符,来区分DB信息块
if((linebuf[0]=='#')||(linebuf[0]=='\0')||(linebuf[0]=='\r')||(linebuf[0]=='\n'))
{
if (lv_dbconf.Connect.size()>0) //假如遇到换行,空行 注解
{ //并且结构体变量有东西,则把它放进数组中
dblist.push_back(lv_dbconf);
lv_dbconf.Connect.clear();
lv_dbconf.Password.clear();
lv_dbconf.User.clear();
lv_dbconf.classA.clear();
lv_dbconf.classB.clear();
lv_dbconf.classC.clear();
lv_dbconf.dbname.clear();
}
continue; //结束本次循环,继续读行数据
}
tmp_line=linebuf; //把字符数组赋值给行字符串变量
linebuf_size=tmp_line.size(); //获得真实行大小
position = 0;
for ( int i=0;i
{
if(tmp_line[i]=='=')
{
position = i;
break;
}
}
key.clear();
key.append(tmp_line,0,position); //获取等号前的KEY
value.clear();
if(key=="DBNAME")
{ //获取KEY对应的VALUE值
value.append(tmp_line,position+1,linebuf_size-7);
lv_dbconf.dbname=value; //把VALUE值赋值给结构体变量
continue;
}
if(key== "CLASSA")
{
value.append(tmp_line,position+1,linebuf_size-6);
lv_dbconf.classA=value;
continue;
}
if(key== "CLASSB")
{
value.append(tmp_line,position+1,linebuf_size-6);
lv_dbconf.classB=value;
continue;
}
if(key== "CLASSC")
{
value.append(tmp_line,position+1,linebuf_size-6);
lv_dbconf.classC=value;
continue;
}
if(key== "USER")
{
value.append(tmp_line,position+1,linebuf_size-5);
lv_dbconf.User=value;
continue;
}
if(key== "PASSWD")
{
value.append(tmp_line,position+1,linebuf_size-7);
lv_dbconf.Password=value;
continue;
}
if(key== "CONN")
{
value.append(tmp_line,position+1,linebuf_size-5);
lv_dbconf.Connect=value;
continue;
}
}
if (lv_dbconf.Connect.size()>0) //读完文件后,结构体变量还有东西,放入数组中
{
dblist.push_back(lv_dbconf);
lv_dbconf.Connect.clear();
lv_dbconf.Password.clear();
lv_dbconf.User.clear();
lv_dbconf.classA.clear();
lv_dbconf.classB.clear();
lv_dbconf.classC.clear();
lv_dbconf.dbname.clear();
}
db_config_file.close(); //关闭文件
//最后数组返回给了MAIN,因为通过地址传,非值传。
}
void Filter_DbList(vector &Filter_dblist,stc_dbFilter stc_Filter)
{
vector tmp_dblist; //临时DB配置列表
vector::iterator iter; //DB配置列表的矢代器,说白了是指针。
tmp_dblist=Filter_dblist; //把DB配置文件赋给临时变量
if(!stc_Filter.m_s_classA.empty()) //非空继续,主函数对过滤条件如果NULL就置空
{
for (iter=tmp_dblist.begin();iter!=tmp_dblist.end();) //循环遍历DB列表
{
if((*iter).classA !=stc_Filter.m_s_classA) //如果DB列表A类与过滤条件A不等
{
tmp_dblist.erase(iter); //则删除他
}
else
{
++iter; //单独拿出来,是因为erase操作自动指向下一个元素
}
}
}
if(!stc_Filter.m_s_classB.empty())
{
for (iter=tmp_dblist.begin();iter!=tmp_dblist.end();)
{
if((*iter).classB!=stc_Filter.m_s_classB)
{
tmp_dblist.erase(iter);
}
else
{
++iter;
}
}
}
if(!stc_Filter.m_s_classC.empty())
{
for (iter=tmp_dblist.begin();iter!=tmp_dblist.end();)
{
if((*iter).classC!=stc_Filter.m_s_classC)
{
tmp_dblist.erase(iter);
}
else
{
++iter;
}
}
}
if(!stc_Filter.m_s_dbname.empty())
{
for (iter=tmp_dblist.begin();iter!=tmp_dblist.end();)
{
if((*iter).dbname!=stc_Filter.m_s_dbname)
{
tmp_dblist.erase(iter);
}
else
{
++iter;
}
}
}
Filter_dblist=tmp_dblist; //最后把删除信息的列表,再赋值回。传给MAIN函数。
}
void Load_SqlConf(vector &sqlList) //装入SQL配置文件
{
char linebuf[1024];
int position=0;
int linebuf_size=0;
stc_sqlconf lstc_sqlconf;
string key;
string value;
string tmp_line;
ifstream sqlconf_file;
sqlconf_file.open("sql.conf",ios::in); //与装入DB配置文件差不多
if(sqlconf_file==NULL)
{
cout<
exit(1);
}
while(!sqlconf_file.eof())
{
sqlconf_file.getline(linebuf,1024);
if((linebuf[0]=='#')||(linebuf[0]=='\r')||(linebuf[0]=='\n'))//这里判断第一个字符,并且取消了\0空格
{
if (lstc_sqlconf.sqlid.size()>0)
{
sqlList.push_back(lstc_sqlconf); //压入数组并清空结构体变量值
lstc_sqlconf.sqlid.clear();
lstc_sqlconf.sqltype.clear();
lstc_sqlconf.sqltext.clear();
}
continue;
}
tmp_line=linebuf;
linebuf_size=tmp_line.size();
position = 0;
if(tmp_line.size()>0)
{
for ( int i=0;i
{
if(tmp_line[i]=='=') //找到等号位置
{
position = i;
break;
}
}
if (position==0) //如果发现该行没有等号,意味着是SQL分成了多行
{
if(lstc_sqlconf.sqltext.size()>0) //判断SQL文本变量是否有值,有意味着现在读取的是第二行
{
lstc_sqlconf.sqltext.append(" "); //使用APPEN向后添加个空格,防止行与行之间没有空格
lstc_sqlconf.sqltext.append(tmp_line);//把SQL剩余的行添加进去
tmp_line.clear();
}
continue;
}
}
if(tmp_line.size()<=0)
{
if (lstc_sqlconf.sqlid.size()>0)
{
sqlList.push_back(lstc_sqlconf); //压入数组并清空结构体变量值
lstc_sqlconf.sqlid.clear();
lstc_sqlconf.sqltype.clear();
lstc_sqlconf.sqltext.clear();
}
continue;
}//\0 配置文件有空行,则放弃读取处理
key.clear();
key.append(tmp_line,0,position); //读取KEY
if(key=="SQLID") //KEY分类处理
{
value.clear(); //读取VALUE
value.append(tmp_line,position+1,linebuf_size-6);
lstc_sqlconf.sqlid=value;
continue;
}
if(key=="SQLTYPE")
{
value.clear();
value.append(tmp_line,position+1,linebuf_size-8);
lstc_sqlconf.sqltype=value;
continue;
}
if(key=="SQLTEXT") //SQL的第一行在这里读取
{
value.clear();
value.append(tmp_line,position+1,linebuf_size-8);
lstc_sqlconf.sqltext=value;
continue;
}
}
if (lstc_sqlconf.sqlid.size()>0) //把最后一个配置压入数组
{
sqlList.push_back(lstc_sqlconf);
lstc_sqlconf.sqlid.clear();
lstc_sqlconf.sqltype.clear();
lstc_sqlconf.sqltext.clear();
}
sqlconf_file.close(); //关闭SQL配置文件
}
void Filter_SqlList(vector &sqlList,string sql_id) //筛选SQL
{
vector::iterator iter;
if(!sql_id.empty())
{
for (iter=sqlList.begin();iter!=sqlList.end();)
{
if((*iter).sqlid !=sql_id)
{
sqlList.erase(iter);
}
else
{
++iter;
}
}
}
else
{
cout<
exit(1);
}
}
void ConnDb_ExecQuery(vector &dblist,vector &sqlList) //连接数据库并执行SQL
{
Environment *env=NULL;
Connection *conn=NULL;
Statement *stmt=NULL;
ResultSet *rset=NULL; //OCCI接口的环境对象,连接对象,语句对象,结果集对象
if(dblist.size()<=0) //对传入参数判断
{
cout<
exit(1);
}
if(sqlList.size()<=0)
{
cout<
exit(1);
}
env = Environment::createEnvironment(Environment::DEFAULT); //环境对象初始化
for (int i=0;i
{
try
{ conn =env->createConnection(dblist[i].User,dblist[i].Password,dblist[i].Connect);//创建连接对象
if(conn!=NULL)
cout<
else
cout<
stmt=conn->createStatement(sqlList[0].sqltext); //创建语句对象
if(sqlList[0].sqltype=="QUERY")
{
cout<
rset=stmt->executeQuery();// this is fix select
vectorQueryColumnList=rset->getColumnListMetaData();
unsigned int col_size=QueryColumnList.size();
for (int x=0;x
{
cout<
}
cout<
cout<
// vector::iterator iter;
// if(!QueryColumnList.empty())
// {
// for (iter=QueryColumnList.begin();iter!=QueryColumnList.end();iter++)
// {
// string ColName=iter->getString(MetaData::ATTR_NAME);
// cout<
// }
//
// }
// }
//display line value
while(rset->next())
{
for (int col = 0; col < col_size; col++)
{
string reStr=rset->getString(col+1).empty() ? " ":rset->getString(col+1).c_str();
cout<
}
cout<
}
}
if(sqlList[0].sqltype=="DML")
{
cout<
stmt->setAutoCommit(true);
int ResulRow=stmt->executeUpdate();
cout<
}
if(sqlList[0].sqltype=="DDL")
{
cout<
stmt->executeUpdate();
cout<
}
if(sqlList[0].sqltype=="ANONY")
{
cout<
stmt->execute();
cout<
}
//正常情况下释放对象 必须TRY挂号里,
if (rset !=NULL) //处理查询语句的结果集对象释放
{
stmt->closeResultSet(rset);
}
conn->terminateStatement(stmt);
env->terminateConnection(conn);
}
catch(SQLException e) //SQL异常处理 C++ catch后会执行后面的正常代码 而不是直接退出。其他DB还要执行不能EXIT(1)
{
cout<
//打印异常信息后关闭所有对象
if (rset !=NULL) //执行非查询语句时,结果集对象是没有的。
{
stmt->closeResultSet(rset);
}
conn->terminateStatement(stmt);
env->terminateConnection(conn);
}
//C++ 没有FINALLY
}
Environment::terminateEnvironment(env); //环境对象放在循环后
}
下面是数据库连接信息配置文件:
#KEY必须大写,遵循实列的KEY,不能多也不能少一个字符.VALUE无所谓
DBNAME=sharkdb
CLASSA=TEST
CLASSB=PLPM
CLASSC=JN
USER=scott
PASSWD=123456
CONN=192.168.2.21:1521/SHARKDB
#2232
DBNAME=sharkdb
CLASSA=DEV
CLASSB=PLPM
CLASSC=JN
USER=scott
PASSWD=123456
CONN=192.168.2.22:1521/SHARKDB
DBNAME=sharkdb
CLASSA=PRODUC
CLASSB=PLPM
CLASSC=JN
USER=scott
PASSWD=123456
CONN=192.168.2.23:1521/SHARKDB
#HAI WAI
DBNAME=sharkdb
CLASSA=TEST
CLASSB=PLPM
CLASSC=HW
USER=scott
PASSWD=123456
CONN=192.168.2.24:1521/SHARKDB
DBNAME=sharkdb
CLASSA=DEV
CLASSB=PLPM
CLASSC=HW
USER=scott
PASSWD=123456
CONN=192.168.2.25:1521/SHARKDB
DBNAME=sharkdb
CLASSA=PRODUC
CLASSB=PLPM
CLASSC=HW
USER=scott
PASSWD=123456
CONN=192.168.2.26:1521/SHARKDB
下面是SQL语句配置文件:
# sqlid MUST ONLY
# 这里KEY必须大写,其中TYPE的VALUE 必须大写 类型选择QUERY DML DDL
# TEXT 不区分大小写,一个SQL可以多行,注意每行必须完整的语句,不能 from user_\ 第二行接 objects
# SQL 后面不可有分号 ;
SQLID=9876523
SQLTYPE=QUERY
SQLTEXT=SELECT SYSDATE FROM DUAL
# select * from user_objects
SQLID=8766686
SQLTYPE=QUERY
SQLTEXT= SELECT OBJECT_NAME,OBJECT_TYPE,CREATED,LAST_DDL_TIME from user_objects
SQLID=123456
SQLTYPE=QUERY
SQLTEXT=SELECT * FROM EMP
SQLID=123457
SQLTYPE=QUERY
SQLTEXT= SELECT
EMPNO,
ENAME,
JOB,
SAL
FROM EMP
SQLID=123458
SQLTYPE=DML
SQLTEXT= INSERT INTO EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO)
VALUES('7935','SHARK','DBA','7782',TO_DATE('1982-01-23 00:00:00','YYYY-MM-DD HH24:MI:SS'),15000,79.78,'10')
SQLID=123459
SQLTYPE=DML
SQLTEXT=UPDATE EMP SET SAL=SAL+1000 WHERE ENAME='TURNER'
SQLID=123450
SQLTYPE=DDL
SQLTEXT=CREATE TABLE MY_OBJECT AS SELECT * FROM USER_OBJECTS
SQLID=123451
SQLTYPE=DDL
SQLTEXT=ALTER TABLE MY_OBJECT ADD IS_DELETE NUMBER(1) DEFAULT 0
SQLID=123452
SQLTYPE=DDL
SQLTEXT=CREATE INDEX IX_MYOBJECT_DDLTIME ON MY_OBJECT(LAST_DDL_TIME)
SQLID=123453
SQLTYPE=ANONY
SQLTEXT=begin DBMS_STATS.GATHER_TABLE_STATS('SCOTT','MY_OBJECT',DEGREE=>1,CASCADE=>TRUE); end;
目前测试的是ORACLE 11.2.0.4版本 11.9.0不支持。另外没测试过AS SYSDBA角色登录。