注:本文基于LightDB的13.8-23.3版本
通常,c语言程序访问和操作PG系的数据库时,我们会使用PG提供的libpq,这是PG官方提供的一套c语言API,功能比较强大,但是使用比较繁琐且不优雅。而ecpg作为嵌入式的SQL,可以通过某些特殊的标记直接将SQL语句嵌入到c语言源程序中,使得代码更加简洁易读。
嵌入式 SQL 程序(*.pgc)的工作原理是通过嵌入式 SQL 预处理器,将源代码(*.pgc)转换成一个普通 c 程序(*.c),而这个c程序中使用了libpq的库函数,因此经过编译链接后生成的可执行程序可以与PG数据库进行通信。所以可以将ecpg理解为在libpq库之上抽象了一层新的更易用更简洁的接口。
给个最简单的例子来直观感受下ecpg,可以看到只需要在SQL前面标记"EXEC SQL",程序执行过程中就能执行SQL语句了
#include
EXEC SQL WHENEVER SQLERROR SQLPRINT;
int
main()
{
EXEC SQL BEGIN DECLARE SECTION;
char dbname[1024];
const char *testdb1 = "[email protected]";
const char *user = "lightdb";
const char *passwd = "!QAZ2wsx";
EXEC SQL END DECLARE SECTION;
EXEC SQL CONNECT TO "[email protected]" as oracle_conn user :user/:passwd;
/* 这个查询将在最近打开的数据库 "oracle" 中执行 */
EXEC SQL SELECT current_database() INTO :dbname;
printf("current=%s (should be oracle)\n", dbname);
/* 创建表 */
EXEC SQL CREATE TABLE if not exists foo (a integer, b text);
EXEC SQL CREATE UNIQUE index if not exists num1 ON foo(a);
EXEC SQL INSERT INTO foo values(1,'aa');
EXEC SQL commit;
printf("table foo created\n", dbname);
EXEC SQL DISCONNECT ALL;
printf("all connections released\n", dbname);
return 0;
}
简单说就是LightDB支持在嵌入式SQL程序中的匿名块中直接对c语言变量进行读写,而且使用方法及其简单,仅需在c程序变量前添加一个冒号,即可在匿名块中使用该c程序变量,详见代码中的retCode变量。
注:LightDB为了更好地兼容Oracle数据库,引入了PL/oraSQL过程语言,这里对PL/oraSQL就不展开了,感兴趣的可以参考官网说明。
#include
EXEC SQL WHENEVER SQLERROR SQLPRINT;
int
main()
{
EXEC SQL BEGIN DECLARE SECTION;
char dbname[1024];
const char *testdb1 = "[email protected]";
const char *user = "lightdb";
const char *passwd = "!QAZ2wsx";
int retCode = 0;
EXEC SQL END DECLARE SECTION;
EXEC SQL CONNECT TO "[email protected]" as oracle_conn user :user/:passwd;
/* 这个查询将在最近打开的数据库 "oracle" 中执行 */
EXEC SQL SELECT current_database() INTO :dbname;
printf("current=%s (should be oracle)\n", dbname);
/* 创建表 */
EXEC SQL CREATE TABLE if not exists foo (a integer, b text);
EXEC SQL CREATE UNIQUE index if not exists num1 ON foo(a);
EXEC SQL commit;
printf("table foo created\n", dbname);
EXEC SQL
Do $$
BEGIN
begin
insert into foo values(1,'aa');
:retCode := 1;
exception when others then
:retCode := -1;
end;
END;
$$ Language plorasql;
EXEC SQL commit;
if(1 == retCode){
printf("anonymous block execution success\n");
} else {
printf("anonymous block execution failure\n");
}
EXEC SQL DISCONNECT ALL;
printf("all connections released\n", dbname);
return 0;
}
c程序员习惯使用//注释,而存储过程程序员习惯使用--注释,LightDB索性就在ecpg的内嵌存储过程中,将两种注释方式都支持了,当然传统的/**/注释方式也是支持的。
#include
EXEC SQL WHENEVER SQLERROR SQLPRINT;
int
main()
{
EXEC SQL BEGIN DECLARE SECTION;
char dbname[1024];
const char *testdb1 = "[email protected]";
const char *user = "lightdb";
const char *passwd = "!QAZ2wsx";
int retCode = 0;
EXEC SQL END DECLARE SECTION;
EXEC SQL CONNECT TO "[email protected]" as oracle_conn user :user/:passwd;
/* 这个查询将在最近打开的数据库 "oracle" 中执行 */
EXEC SQL SELECT current_database() INTO :dbname;
printf("current=%s (should be oracle)\n", dbname);
EXEC SQL
Do $$
BEGIN
begin
insert into foo values(2,'aa');
--insert into foo values(3,'aa');
//insert into foo values(4,'aa');
/*insert into foo values(5,'aa');*/
:retCode := 1;
exception when others then
:retCode := -1;
end;
END;
$$ Language plorasql;
EXEC SQL commit;
if(1 == retCode){
printf("anonymous block execution success\n");
} else {
printf("anonymous block execution failure\n");
}
EXEC SQL DISCONNECT ALL;
printf("all connections released\n", dbname);
return 0;
}
在Oracle兼容模式下,LightDB内核已经支持Oracle(+)的外连接写法,目前ecpg中也支持此写法。
初始数据如下:
#include
EXEC SQL WHENEVER SQLERROR SQLPRINT;
int
main()
{
EXEC SQL BEGIN DECLARE SECTION;
char dbname[1024];
const char *testdb1 = "[email protected]";
const char *user = "lightdb";
const char *passwd = "!QAZ2wsx";
int cntOuter = 0;
int cntInner = 0;
int retCode = 0;
EXEC SQL END DECLARE SECTION;
EXEC SQL CONNECT TO "[email protected]" as oracle_conn user :user/:passwd;
/* 这个查询将在最近打开的数据库 "oracle" 中执行 */
EXEC SQL SELECT current_database() INTO :dbname;
printf("current=%s (should be oracle)\n", dbname);
EXEC SQL
Do $$
BEGIN
begin
select count(*) into :cntOuter from foo,foo1 where foo.a=foo1.a(+);
select count(*) into :cntInner from foo,foo1 where foo.a=foo1.a;
exception when others then
:retCode := -1;
end;
END;
$$ Language plorasql;
EXEC SQL commit;
if(0 != retCode) {
printf("anonymous block execution failure\n");
} else {
printf("cntOuter=%d, cntInner=%d\n",cntOuter,cntInner);
}
EXEC SQL DISCONNECT ALL;
printf("all connections released\n", dbname);
return 0;
}
执行结果如下: