C++アプリケーション

PostgreSQL 9.1.1文書
前のページ | 巻戻し | 第 33章ECPG - C言語による埋め込みSQL | 早送り | 次のページ

# 33.13. C++アプリケーション

ECPGはC++アプリケーションを多少の制限がありますがサポートします。 本節ではいくつかの注意を説明します。

`ecpg`プリプロセッサはC（またはCのようなもの）と埋め込みSQLコマンドで記述された入力ファイルを取り、埋め込みSQLコマンドをC言語の小塊に変換し、最終的に`.c`ファイルを作成します。 `ecpg`が生成するC言語の小塊で使用されるライブラリ関数のヘッダファイル定義は、C++で使用される場合`extern "C" { ... }`で囲まれます。 このためC++でも継ぎ目なく動作するはずです。

しかし一般的には、`ecpg`プリプロセッサはCのみを理解しています。 C++言語の特殊な構文や予約語を取り扱いません。 このため、C++に特化した複雑な機能を使用するC++アプリケーションコードの中に記述された埋め込みSQLコードの一部は、正しく前処理することに失敗する、または想定通りに動作しないかもしれません。

C++アプリケーションで埋め込みSQLコードを使用する安全な方法は、ECPGの呼び出しをC++アプリケーションコードがデータベースにアクセスするために呼び出し、残りの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`の技術的な制限を理解しているのであれば、ECPG機能を使用するC++アプリケーションを実現するためには、リンク段階でCオブジェクトとC++オブジェクトをリンクする方が、C++コード内で埋め込みSQLコマンドを直接記述することより優れているという結論に至るでしょう。 本節では、簡単な例を用いて、C++アプリケーションコードから埋め込みSQLコマンドを分離する方法について説明します。 この例では、アプリケーションはC++で実装し、PostgreSQLサーバに接続するためにCおよびECPGを使用します。

Cファイル（`*.pgc`）、ヘッダファイル、C++ファイルという３種類のファイルを作成しなければなりません。

`test_mod.pgc`

  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`でインクルードされます。 このファイルは、C++モジュールからリンクされますので、宣言を囲む`extern "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

最後に、C++コンパイラドライバを用いて`test_cpp.o`および`test_mod.o`というオブジェクトファイルを実行形式ファイルにリンクします。

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

前のページ | ホーム | 次のページ
ラージオブジェクト | 上に戻る | 埋め込みSQLコマンド