PostgreSQL 9.4.4 中文手册
上一页 | 上一级 | 章 33. ECPG - 在C中嵌入SQL | 下一页

# 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.pgc`到`test_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.o` 和`test_mod.o`到一个可执行文件中，使用C++编译器驱动：

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

上一页 | 起始页 | 下一页
大对象 | 上一级 | 嵌入的SQL命令