数据类型¶
数据库类型和C代码中的类型对应关系,可跨类型进行隐式转换,但不推荐。
| 数据库类型 | C类型 | OTL类型 | 备注 |
|---|---|---|---|
| Int | Int | <int> | |
| smallint | Short int | <short> | |
| bigint | double | <double> | bigint统一用double存储 |
| Number | double | <double> | |
| Decimal | double | <double> | |
| numeric | double | <double> | |
| real | double | <double> | |
| Double | double | <float> | |
| float | double | <int> | |
| char | char | <char[n]> | n为1~8000 |
| varchar | char | <char[n]> | n为1~8000 |
| text | char | <char[n]> | n为1~8000 |
| binary | raw | <raw(n)> | n为1~8000 |
| varbinary | raw | <raw(n)> | n为1~8000 |
| date | otl_datetime | <timestamp> | |
| time | otl_datetime | <timestamp> | |
| timestamp | otl_datetime | <timestamp> | |
| clob | otl_long_string | <clob> | |
| blob | otl_long_string | <blob> |
连接数据库¶
在做操作之前,程序肯定需要与数据库建立一个连接,方式如下:
otl_connect::otl_initialize();
db.rlogon("URL");
URL连接字符串的格式有2中:
第一种为:用户/密码@IP:端口/数据库实例名,例如:sysdba/szoscar55@localhost:2003/osrdb
第二种为:用户/密码@服务名,服务名需要配置,在$SZ_OSCAR_HOME/admin/tnsnames.aci中默认有个配置如下:acidb1 = localhost:2003/osrdb。有了这个配置,我们连接的URL可写为:sysdba/szoscar55@ osrdb1
注意:数据库连接不是线程安全接口,请不要在多线程中同时使用一个数据库连接对象。
执行SQL语句¶
OTL中sql语句的执行需要用到一个游标对象,他用了执行sql并保存sql的,创建游标对象的类为otl_cursor,比如:
otl_cursor stmt_cur; // stmt_cur为实例化的sql执行对象
实例化执行对象后,就可以执行sql了:
stmt_cur.direct_exec( db,"drop table test_tab",otl_exception::disabled);
stmt_cur.direct_exec( db, "create table test_tab(c1 int, c2 varbinary(700),c3 number(10,3),c4 varchar(20))");
stmt_cur.direct_exec( db, "insert into test_tab values (1, 0x111,22.33,'aaaaaa')");
获取结果¶
当我们执行完一个查询后,如何获得我们需要的结果,这里要非常值得注意,获得结果的过程是将数据库中存储的数据转换到程序中的变量中。那这里就涉及到数据库中的类型在程序中应该用那种类型的变量来获取。我这里不详细阐述,数据类型的支持请参考“数据类型支持章节”。
下面以一个例子说明如何获得结果:
--create table test_tab(c1 int, c2 varbinary(700),c3 number(10,3),c4 varchar(20))
void select()
{
otl_long_string f2(700); // 定义long string 变量
otl_column_desc* desc;
int desc_len;
int f1;
otl_stream i(1,"select * from test_tab order by c1",db);
otl_stream_read_iterator<otl_stream,otl_exception,otl_lob_stream> rs;
desc=i.describe_select(desc_len);
………….元数据获取……….
rs.attach(i); // 将迭代器加入到数据量i中
// 执行,查询所有的数据
while(rs.next_row()){
rs.get(1,f1);
rs.get(2,f2);
cout<<"\t\tc1="<<f1<<", c2="<<f2.v<<", len="<<f2.len()<<endl;
}
}
获取元数据¶
当我们做了一个查询后,可能我不知这个查询返回的有多少列,每个列的类型、长度、浮点数、精度、是否为NULL等属性也不知,那么如何获得这些信息,以便在程序中更好的处理数据?元数据的获取帮助我们完成这个需求:
--create table test_tab(c1 int, c2 varbinary(700),c3 number(10,3),c4 varchar(20))
void select()
{
otl_long_string f2(700); // 定义long string 变量
otl_column_desc* desc;
int desc_len;
int f1;
otl_stream i(1,"select * from test_tab where c1>=:f11<int> and c1<=:f12<int>*2 order by c1",db);
otl_stream_read_iterator<otl_stream,otl_exception,otl_lob_stream> rs;
desc=i.describe_select(desc_len);
for(int n=0;n<desc_len;++n){
cout<<" 列名="<<desc[n].name;
cout<<",类型="<<desc[n].dbtype;
cout<<",otl_var_dbtype="<<desc[n].otl_var_dbtype;
cout<<",长度="<<desc[n].dbsize;
cout<<",浮点数="<<desc[n].scale;
cout<<",精度="<<desc[n].prec;
cout<<",是否为空="<<desc[n].nullok<<endl;
}
rs.attach(i); // 将迭代器加入到数据量i中
……………………..
}
参数绑定¶
参数绑定执行为应用程序提供了方便,避免拼写大量的无法复用的sql。参数绑定方式可以一次执行sql语句,传入不同参数后多次执行。参数绑定的形式为: :pname<type>,pname为参数名称,可以随意制定;type为你要绑定的变量类型,类型对应关系请查看”数据类型支持”章节。
使用举例:
//插入条数据
void insert_bind()
{
otl_long_string f2(700); // 定义long string 类型
char f4[20];
otl_stream o(1,"insert into test_tab values(:f1<int>,:f2<raw[700]>,:f3<double>,:f4<char[20]>)",db);
for(int i=1;i<=20;++i){
for(int j=0;j<699;++j)
f2[j]='a';
f2[699]='x';
f2.set_len(700);
strcpy(f4,"aaaaa");
o<<i<<f2<<33.44<<f4;//传入参数方式使用<<符号重载功能,执行,避免了每次都写insert的烦恼
}
cout<<" 成功的用参数绑定的方式向test_tab表插入20条数据!"<<endl<<endl;
}
大对象操作¶
OTL大对象的读写支持CLOB和CLOB。
大对象的写¶
直接用例子说明:
{
//通过OTL_LOB流的方式写入clob的数据
otl_lob_stream lob;
otl_long_string f3(30000);
otl_cursor stmt_cur;
int n = 0;
stmt_cur.direct_exec( db,"drop table test_tab_lob",otl_exception::disabled);
stmt_cur.direct_exec( db, "create table test_tab_lob(f1 int, f2 clob)");
otl_stream i(1,"insert into test_tab_lob values(2,empty_clob()) returning f2 into :f2<clob>",db); //采用returning的语法进行返回插入的空lob
i<<lob; //将lob放入i中
//通过for循环,向lob对象中放入需要插入的数据,结束数据添加用lob的close方法
for(int j=0;j<5000;j++)
{
f3[j]='*';
}
f3[5000]='?';
f3.set_len(5001);
lob.set_len(5001);
lob<<f3;//添加数据到lob中
lob<<f3; //追加数据到lob中
lob.close();
}
大对象的读¶
大对象的度有三种方式:
第一种方式,通过字符串的方式获取clob的数据,最大获取长度32760字节,适合小数据量的lob,获取性能高。
{
otl_long_string f2(100000); // 定义 long string 变量
int f1;
otl_cursor stmt_cur;
stmt_cur.direct_exec( db,"drop table test_tab_lob",otl_exception::disabled);
stmt_cur.direct_exec( db, "create table test_tab_lob(f1 int, f2 clob)");
stmt_cur.direct_exec( db, "insert into test_tab_lob values(1, repeat('a',30000))");
otl_stream i(10,"select f1, f2 from test_tab_lob order by f1",db);
otl_stream_read_iterator<otl_stream,otl_exception,otl_lob_stream> rs;
rs.attach(i); // 将迭代器加入到数据量i中
while(rs.next_row()){
rs.get(1,f1);
rs.get(2,f2);
cout<<"\t\tf1="<<f1<<", f2="<<f2.v<<", len="<<f2.len()<<endl<<endl;
}
}
第二种方式,通过OTL_LOB流的方式获取clob的数据
{
int f1;
otl_lob_stream * lob;
otl_long_string f3(30000);
otl_cursor stmt_cur;
int n = 0;
stmt_cur.direct_exec( db,"drop table test_tab_lob",otl_exception::disabled);
stmt_cur.direct_exec( db, "create table test_tab_lob(f1 int, f2 clob)");
stmt_cur.direct_exec( db, "insert into test_tab_lob values(1, repeat('a',300000))");
otl_stream i(10,"select f1, f2 from test_tab_lob order by f1",db);
otl_stream_read_iterator<otl_stream,otl_exception,otl_lob_stream> rs;
i.set_lob_stream_mode(true); //这条语句是必须有的,如果没有无法获取lob对象的数据
rs.attach(i); // 将迭代器加入到数据量i中
while(rs.next_row()){
rs.get(1,f1);
rs.get(2,lob);
while(!lob->eof()){
n++;
(*lob)>>f3;//一次获取30000字符,直到lob的末尾
cout<<" chunk #"<<n;
cout<<", f3="<<f3[0]<<f3[f3.len()-1]<<", len="<<f3.len()<<endl;
}
}
}
第三种方式,通过OTL_LOB流的方式获取clob的数据
{
int f1;
otl_lob_stream lob;
otl_long_string f3(30000);
otl_cursor stmt_cur;
int n = 0;
stmt_cur.direct_exec( db,"drop table test_tab_lob",otl_exception::disabled);
stmt_cur.direct_exec( db, "create table test_tab_lob(f1 int, f2 clob)");
stmt_cur.direct_exec( db, "insert into test_tab_lob values(1, repeat('a',300000))");
otl_stream i(10,"select f1, f2 from test_tab_lob order by f1",db);
while(!i.eof())
{
i>>f1;
i>>lob; //和第二种方式相比,只是获得lob对象的方式有所区别
while(!lob.eof()){
n++;
lob>>f3;
cout<<" chunk #"<<n;
cout<<", f3="<<f3[0]<<f3[f3.len()-1]<<", len="<<f3.len()<<endl;
}
}
}
异常处理和错误获取¶
神通OTL的异常处理比较简单,异常类只有一种异常类型:otl_exception, otl_exception类中有几个常用成员:otl_exception-> msg,用户显示错误信息;otl_exception-> sqlstate,显示错状态号;otl_exception-> stm_text ,显示执行错误的sql语句;otl_exception->var_info,其他错误信息。使用举例:
try{
//初始化、连接
otl_connect::otl_initialize();
db.rlogon("sysdba/szoscar55@localhost:2003/osrdb");
}
catch(otl_exception& p){
cerr<<p.msg<<endl;
cerr<<p.sqlstate<<endl;
cerr<<p.stm_text<<endl;
cerr<<p.var_info<<endl;
}
一个简单示例¶
#include "otlv4.h"
#include <stdlib.h>
#include <iostream>
using namespace std;
int main()
{
otl_connect::otl_initialize();
otl_connect db;
try{
db.rlogon("sysdba/szoscar55@localhost:2003/osrdb");
cout<<"登录成功\n";
// stmt_cur为实例化的sql执行对象
otl_cursor stmt_cur;
stmt_cur.direct_exec( db,"drop table test_tab",otl_exception::disabled);
stmt_cur.direct_exec( db, "create table test_tab(c1 int, c2 varbinary(700),c3 number(10,3),c4 varchar(20))");
stmt_cur.direct_exec( db, "insert into test_tab values (1, 0x111,22.33,'aaaaaa')");
cout<<"操作成功\n";
}
catch(otl_exception& p)
{
cerr<<p.msg<<endl;
}
}
编译命令
g++ -o otltest -I$SZ_OSCAR_HOME/drivers/aci/include/ -I. -lpthread -laci otl.c -DOTL_ORA11G
执行
./otltest