绑定完请刷新页面
取消
刷新

分享好友

×
取消 复制
使用IBPP在C++中操作FireBird/Interbase数据库
2022-06-29 14:22:44

转载地址:http://blog.sina.com.cn/s/blog_648d306d0100swhc.html

FireBird是一种小巧的关系型数据库,它有多种版本,包括服务器版(象MySQL),单机版(象Access)以及嵌入式(象SQLite)。而且不管是服务器版还是嵌入式版它都完整支持视图、触发器、存储过程等SQL特性。

问题是它提供的C API“不太友好”,不容易掌握(特别是我),所以我一直只会在C++Builder里编程使用FireBird(因为FireBird源于 Borland的InterBase,VCL库自带了InterBase的组件),直到有一天我发现了IBPP...

IBPP是 一个FireBird/Interbase数据库API的C++包装,使用起来也比较简单,只要把IBPP源码目录里的 "core/all_in_one.cpp"加入工程,在代码中包含头文件"ibpp.h",后根据操作系统预定义一个IBPP_WINDOWS或 IBPP_UNIX的宏即可。

另外,当然还要安装FireBird客户端,如果只是学习,我们可以下载嵌入式版本。IBPP首先要找到FireBird的动态库,在Windows下, IBPP在下面的路径中查找:

  • 在程序目录下查找fbembed.dll
  • 在程序目录下查找fbclient.dll
  • 依据DefaultInstance注册表键值查找fbclient.dll
  • 在系统定义位置查找fbclient.dll
  • 在系统定义位置查找gds32.dll

FireBird主页:http://www.ibphoenix.com

IBPP主页:http://www.ibpp.org

关于FireBird的中文教程我推荐姚启红编著的《Borland InterBase7.0 应用开发指南》(网上一找一大堆)。

例一,基本应用

  1. #include <iostream>
  2. #include <ibpp.h>
  3. using namespace std;
  4.  
  5. //数据库名,根据你的情况更改。
  6. const charg_szDBName "d:\\test.fdb";
  7. //服务器名,针对服务器版本。对于嵌入式,它应该是""
  8. const charg_szServerName "";
  9.  
  10. //这里的用户名和密码是FireBird默认值,对于服务器版,用你自己的密码
  11. //对于嵌入式,就是这个(FireBird嵌入式版没有加密功能)。
  12. const char   g_szUserName "SYSDBA";
  13. const charg_szPassword "masterkey";
  14.  
  15. int main()
  16. {
  17.     IBPP::Database db IBPP::DatabaseFactory(g_szServerName,
  18.         g_szDBName,
  19.         g_szUserName,
  20.         g_szPassword);
  21.     //建立数据库
  22.     db->Create(3);
  23.     //连接数据库
  24.     db->Connect();
  25.  
  26.     IBPP::Transaction tr IBPP::TransactionFactory(db);
  27.     tr->Start();
  28.     try{
  29.         IBPP::Statement st IBPP::StatementFactory(db,tr);
  30.         //建立数据表
  31.         st->Execute(
  32.             "CREATE TABLE TESTTABLE("
  33.                ID INTEGER NOT NULL PRIMARY KEY,"
  34.                RNO VARCHAR(10) NOT NULL UNIQUE,"
  35.                SHIFT VARCHAR(5) NOT NULL"
  36.                    CHECK(SHIFT IN('A','B','C','D')),"
  37.                LINE CHAR(20) NOT NULL,"
  38.                SL COMPUTED BY(SHIFT||'.'||LINE),"
  39.                EMP CHAR(20)"
  40.                )"
  41.             );
  42.         tr->CommitRetain();
  43.         //插入数据,华安和小强
  44.         st->Execute(
  45.             "INSERT INTO TESTTABLE(ID,RNO,SHIFT,LINE,EMP)"
  46.             "VALUES(1,'B9527','B','DAZHA','Hua,An')"
  47.         );
  48.         st->Execute(
  49.             "INSERT INTO TESTTABLE(ID,RNO,SHIFT,LINE,EMP)"
  50.             "VALUES(2,'B9528','B','ZHUANGSI','Xiao,Qiang')"
  51.         );
  52.  
  53.         tr->CommitRetain();
  54.         //插入数据,石榴和祝枝山
  55.         st->Execute(
  56.             "INSERT INTO TESTTABLE(ID,RNO,SHIFT,LINE,EMP)"
  57.             "VALUES(3,'B9525','A','DAZHA','Shi,Liu')"
  58.         );
  59.         //SHIFT只能是ABCD,看看写X会有什么情况发生
  60.         st->Execute(
  61.             "INSERT INTO TESTTABLE(ID,RNO,SHIFT,LINE,EMP)"
  62.             "VALUES(4,'B9526','X','DAZHA','Zhu,ZiShang')"
  63.         );
  64.         tr->Commit();
  65.     }
  66.     catch(IBPP::SQLException &e){
  67.         cerr << e.what() << endl;
  68.         tr->Rollback();
  69.     }
  70.  
  71.     tr->Start();
  72.     try{
  73.         IBPP::Statement st IBPP::StatementFactory(db,tr);
  74.         st->Execute("SELECT RNO, EMP FROM TESTTABLE");
  75.         //显示SELECT得到的数据
  76.         while(st->Fetch())
  77.         {
  78.             string rno, emp;
  79.             st->Get("RNO",rno);
  80.             st->Get("EMP",emp);
  81.             cout << "RNO:" << rno << EMP:" << emp << endl;
  82.         }
  83.         tr->Commit();
  84.     }
  85.     catch(IBPP::SQLException &e){
  86.         cerr << e.what() << endl;
  87.         tr->Rollback();
  88.     }
  89. }

要让程序正确执行,就得保证程序能找到FireBird的动态链接库。对于嵌入式版本来说,下载后把压缩包中的fbembed.dll, firebird.conf,firebird.msg,ib_util.dll以及intl文件夹解压到你的程序目录中就可以运行了。对于服务器版,只要安装客户端并把fbclient.dll放到程序目录里就行(当然权限也要有啦)。

上例中使用IBPP的步骤是:

  1. 用工厂函数IBPP::DatabaseFactory生成IBPP::Database实例,然后调用它的Connect()成员变量连接数据库。
  2. 如果要建立数据库的话,使用Database::Create(int dialect)。其中dialect一般取值为3,它的含义如下:
SQL Dialect含义
1兼容InterBase 5.5及更早版本。
21和3的过渡版本。
3InterBase 6.0及以后版本,可以使用分隔符,数字和时间格式。
  1. 使用工厂函数IBPP::TransactionFactory生成IBPP::Transaction实例,然后用它的Start()开始事务,后用Commit()来提交事务或Rollback()撤销事务。
  2. 使用工厂函数IBPP::StatementFactory生成IBPP::Statement实例,然后用它的Execute()来执行SQL命令。
  3. 值 得注意的是,IBPP中的Database,Transaction,Statement等由工厂函数返回的数据都是智能指针类型,它们能够在退出有效域 时自动执行一些保证完整性的操作。(比如我们使用tr->Start()后即便不调用tr->Commit(),在超出tr变量作用域后系统 也会自动调用Commit的)

例二,操作Blob型字段

  1. #include <iostream>
  2. #include <algorithm>
  3. #include <assert.h>
  4. #include <ibpp.h>
  5. using namespace std;
  6.  
  7. //数据库名,根据你的情况更改。
  8. const charg_szDBName "d:\\test.fdb";
  9. //服务器名,针对服务器版本。对于嵌入式,它应该是""
  10. const charg_szServerName "";
  11.  
  12. //这里的用户名和密码是FireBird默认值,对于服务器版,用你自己的密码
  13. //对于嵌入式,就是这个(FireBird嵌入式版没有加密功能)。
  14. const char   g_szUserName "SYSDBA";
  15. const charg_szPassword "masterkey";
  16.  
  17. int main()
  18. {
  19.     IBPP::Database db;
  20.     db IBPP::DatabaseFactory(g_szServerName,
  21.         g_szDBName,
  22.         g_szUserName,
  23.         g_szPassword);
  24.     //连接数据库
  25.     db->Connect();
  26.  
  27.     IBPP::Transaction tr IBPP::TransactionFactory(db);
  28.     tr->Start();
  29.     try{
  30.         IBPP::Statement st IBPP::StatementFactory(db,tr);
  31.         //建立数据表
  32.         st->ExecuteImmediate(
  33.             "CREATE TABLE BlobTable("
  34.                ID INTEGER NOT NULL,"
  35.                RES BLOB)"
  36.             );
  37.         //生成器
  38.         st->ExecuteImmediate(
  39.             "CREATE GENERATOR BlobTable_ID_Gen"
  40.             );
  41.         //触发器
  42.         st->ExecuteImmediate(
  43.             "CREATE TRIGGER BlobTable_BI_ID FOR BlobTable "
  44.             "ACTIVE BEFORE INSERT POSITION 0 "
  45.             "AS "
  46.             "BEGIN "
  47.                IF(NEW.ID IS NULL) THEN "
  48.                    NEW.ID GEN_ID(BlobTable_ID_Gen, 1); "
  49.             "END"
  50.         );
  51.         tr->CommitRetain();
  52.        
  53.         st->Prepare("INSERT INTO BlobTable(RES) VALUES(?)");
  54.         assert(1 == st->Parameters());
  55.         //插入Blob,一块100字节的内存
  56.         {
  57.             IBPP::Blob res IBPP::BlobFactory(db,tr);
  58.             res->Create();
  59.             char buf[100];
  60.             for(int i=0; i<100; i++) buf[i]=i;
  61.             res->Write(buf,sizeof(buf));
  62.             res->Close();
  63.             st->Set(1,res); //个问号
  64.             st->Execute();
  65.         }
  66.         //插入Blob,一串字符串
  67.         {
  68.             st->Set(1,string("HAHAHAHAHAHA..."));
  69.             st->Execute();
  70.         }
  71.         tr->Commit();
  72.     }
  73.     catch(IBPP::SQLException &e){
  74.         cerr << e.what() << endl;
  75.         tr->Rollback();
  76.     }
  77.  
  78.     tr->Start();
  79.     try{
  80.         IBPP::Statement st IBPP::StatementFactory(db,tr);
  81.         st->Execute("SELECT FROM BlobTable");
  82.         //显示SELECT得到的数据
  83.         while(st->Fetch())
  84.         {
  85.             int id;
  86.             IBPP::Blob res IBPP::BlobFactory(db,tr);
  87.  
  88.             st->Get(1,id);
  89.             st->Get(2,res);
  90.            
  91.             //显示Blob内容
  92.             res->Open();
  93.             int size;
  94.             res->Info(&size,NULL,NULL);
  95.             cout << id << size is " << size << endl;
  96.             char c;
  97.             while(res->Read(&c,1))
  98.             {
  99.                 cout << (int)c << ';
  100.             }
  101.             cout << endl;
  102.         }
  103.         tr->Commit();
  104.     }
  105.     catch(IBPP::SQLException &e){
  106.         cerr << e.what() << endl;
  107.         tr->Rollback();
  108.     }
  109. }

本 例连接例一建立的数据库,然后新建一个名为BlobTable的表,里面只有ID和RES字段,而且还为ID字段建立了一个生成器和触发器,这样就可以 让FireBird自动为ID赋值了,具体内容可以看FireBird教程。与例一不同的是这里使用了IBPP::Statement的 ExecuteImmediate()方法,它立即执行其中的SQL语句,而Execute()则有一个先准备、再执行的过程,对于只执行一次的SQL, 可以使用ExecuteImmediate(),如果执行次数较多,则建议使用Execute()。

RES字段是一个Blob型字段,从本例可以看出给Blob字段赋值的方法是:

  1. 用IBPP::Statement的Prepare()方法准备SQL插入语句,其中的Blob字段使用问号?代替。
  2. 用工厂函数IBPP::BlobFactory生成一个IBPP::Blob实例,然后分别调用它的Create(),Write()和Close()输入数据,后用IBPP::Statement的Set()方法写入。
  3. 所有数据准备就绪后,执行IBPP::Statement的Execute()方法。

如果只想往Blob中存放文本数据,也可以直接用IBPP::Statement的Set()方法写入std::string类型。

从Blob字段取值的方法正好相反:

  1. 用IBPP::Statement的Execute()方法或ExecuteImmediate()方法执行SELECT语句。
  2. 使用IBPP::Statement的Fetch()方法提取出当前行的数据。
  3. 使用IBPP::Statement的Get()方法取出指定列的数据,如果是Blob类型,则使用IBPP::Blob实例作为输入。
  4. 后分别调用IBPP::Blob的Open(),Read()和Close()方法取出数据(IBPP::Blob也是一个智能指针类型,所以上例中没有显式地使用Close()关闭)。
分享好友

分享这个小栈给你的朋友们,一起进步吧。

InterBase
创建时间:2022-03-29 15:23:16
InterBase
展开
订阅须知

• 所有用户可根据关注领域订阅专区或所有专区

• 付费订阅:虚拟交易,一经交易不退款;若特殊情况,可3日内客服咨询

• 专区发布评论属默认订阅所评论专区(除付费小栈外)

技术专家

查看更多
  • LCR_
    专家
戳我,来吐槽~