Redrock Postgres 搜索 英文
版本: 9.3 / 9.4 / 9.5 / 9.6 / 10 / 11 / 12 / 13 / 14 / 15 / 16

33.13. C++应用程序

ECPG对C++应用程序有一些有限的支持。本节介绍一些注意事项。

ecpg预处理程序采取写入C(或者类似C)的输入文件,并且 嵌入SQL命令,将嵌入SQL命令转换为C语言块, 最后生成.c文件。 当在C++中使用时, 通过ecpg产生的C语言块使用的库函数的头文件声明 被包裹在extern "C" { ... }块中。 因此他们应该在C++中无缝工作。

一般情况下,然而,ecpg预处理器仅仅了解C;它 不处理特殊语法并且保留C++语言关键字。因此, 写入使用复杂特定C++功能的C++应用程序代码的一些嵌入SQL代码可能 不能正确地被预处理或者可能不会按预期的工作。

在C++应用程序中使用嵌入SQL代码的安全方式是在C模块中隐藏ECPG调用, 其中C++应用程序代码调用访问数据库,并且连同C++代码其余部分一起连接。 参阅第 33.13.2 节获取关于它的更多信息。

33.13.1. 宿主变量范围

ecpg预处理器理解C中变量范围。在C语言中, 这是简单地因为变量范围基于他们的代码块。在C++中, 然而,类成员变量参考来自声明位置的不同代码块。 因此ecpg预处理程序不理解类成员变量的范围。

比如,在下面情况下,ecpg预处理器无法找到 test方法中变量dbname的任何声明, 因此产生错误。

class TestCpp
{
    EXEC SQL BEGIN DECLARE SECTION;
    char dbname[1024];
    EXEC SQL END DECLARE SECTION;

  public:
    TestCpp();
    void test();
    ~TestCpp();
};

TestCpp::TestCpp()
{
    EXEC SQL CONNECT TO testdb1;
}

void Test::test()
{
    EXEC SQL SELECT current_database() INTO :dbname;
    printf("current_database = %s\n", dbname);
}

TestCpp::~TestCpp()
{
    EXEC SQL DISCONNECT ALL;
}

这个代码将产生类似这样的错误。

ecpg test_cpp.pgc
test_cpp.pgc:28: ERROR: variable "dbname" is not declared

为了避免这个范围问题,test方法可以改为使用局部变量作为 中间存储器。但是这个方法仅仅是一个低劣的解决办法,因为 它丑化代码并且降低性能。

void TestCpp::test()
{
    EXEC SQL BEGIN DECLARE SECTION;
    char tmp[1024];
    EXEC SQL END DECLARE SECTION;

    EXEC SQL SELECT current_database() INTO :tmp;
    strlcpy(dbname, tmp, sizeof(tmp));

    printf("current_database = %s\n", dbname);
}

33.13.2. C++应用程序开发与外部C模块

如果你理解C++中ecpg预处理器的这些技术局限性, 你可能得到这样的结论在链接阶段链接中C对象与C++对象使得C++应用程序 使用ECPG功能可能好于在C++代码中直接写一些嵌入SQL命令。

已经创建三种文件:一个C文件(*.pgc), 头文件和C++文件:

test_mod.pgc

执行SQL命令的子程序模块嵌入C中。它将通过预处理器被转换为 test_mod.c

#include "test_mod.h"
#include <stdio.h>

void
db_connect()
{
    EXEC SQL CONNECT TO testdb1;
}

void
db_test()
{
    EXEC SQL BEGIN DECLARE SECTION;
    char dbname[1024];
    EXEC SQL END DECLARE SECTION;

    EXEC SQL SELECT current_database() INTO :dbname;
    printf("current_database = %s\n", dbname);
}

void
db_disconnect()
{
    EXEC SQL DISCONNECT ALL;
}

test_mod.h

C模块中(test_mod.pgc)使用函数声明的头文件通过 test_cpp.cpp被包含。 这个文件在声明周围有一个extern "C"块,因为 它将从C++模块链接。

#ifdef __cplusplus
extern "C" {
#endif

void db_connect();
void db_test();
void db_disconnect();

#ifdef __cplusplus
}
#endif

test_cpp.cpp

该应用程序主要代码,包含main程序和例子中C++类。

#include "test_mod.h"

class TestCpp
{
  public:
    TestCpp();
    void test();
    ~TestCpp();
};

TestCpp::TestCpp()
{
    db_connect();
}

void
TestCpp::test()
{
    db_test();
}

TestCpp::~TestCpp()
{
    db_disconnect();
}

int
main(void)
{
    TestCpp *t = new TestCpp();

    t->test();
    return 0;
}

为了编译应用程序,如下进行。 通过运行ecpg, 转换test_mod.pgctest_mod.c, 使用C编译器通过编译test_mod.c产生test_mod.o

ecpg -o test_mod.c test_mod.pgc
cc -c test_mod.c -o test_mod.o

下一步,使用C++编译器通过编译test_cpp.cpp、 生成test_cpp.o

c++ -c test_cpp.cpp -o test_cpp.o

最后,链接这些对象文件,test_cpp.otest_mod.o到一个可执行文件中,使用C++编译器驱动:

c++ test_cpp.o test_mod.o -lecpg -o test_cpp