無料スクリプト配布のPHP.TO   PHPの実用的なtips PHPマニュアル MySQLマニュアル Apacheマニュアル PostgreSQLマニュアル マニュアル検索    

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++ファイルという3種類のファイルを作成しなければなりません。

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


powered by SEO.CUG.NET