

ECPG a un support limité pour les applications C++. Cette section décrit certains pièges.
   Le préprocesseur ecpg prend un fichier
   d'entrée écrit en C (ou quelque chose qui ressemble à du C) et
   des commandes SQL embarquées, et convertit les commandes SQL
   embarquées dans des morceaux de langage, et finalement génère
   un fichier .c. Les déclarations de fichiers
   d'entête des fonctions de librairie utilisées par les morceaux
   de langage C que génère ecpg sont entourées de
   blocs extern "C" { ... } quand ils sont
   utilisés en C++, ils devraient donc fonctionner de façon transparente
   en C++.
  
   En général, toutefois, le préprocesseur ecpg
   ne comprend que le C; il ne gère pas la syntaxe spéciale et les
   mots réservés du langage C++. Par conséquent, du code SQL embarqué
   écrit dans du code d'une application C++ qui utilise des fonctionnalités
   compliquées spécifiques au C++ pourrait ne pas être préprocessé
   correctement ou pourrait ne pas fonctionner comme prévu.
  
Une façon sûre d'utiliser du code SQL embarqué dans une application C++ est de cacher les appels à ECPG dans un module C, que le code C++ de l'application appelle pour accéder à la base, et lier ce module avec le reste du code C++. Voyez Section 35.13.2 à ce sujet.
    Le préprocesseur ecpg comprend la porté des
    variables C. Dans le langage C, c'est plutôt simple parce que la
    portée des variables ne dépend que du bloc de code dans lequel
    elle se trouve. En C++, par contre, les variables d'instance sont
    référencées dans un bloc de code différent de la position de déclaration,
    ce qui fait que le préprocesseur ecpg ne comprendra
    pas la portée des variables d'instance.
   
    Par exemple, dans le cas suivant, le préprocesseur ecpg
    ne peut pas trouver de déclaration pour la variable dbname
    dans la méthode test, une erreur va donc se produire.
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;
    EXEC SQL SELECT pg_catalog.set_config('search_path', '', false); EXEC SQL COMMIT;
}
void Test::test()
{
    EXEC SQL SELECT current_database() INTO :dbname;
    printf("current_database = %s\n", dbname);
}
TestCpp::~TestCpp()
{
    EXEC SQL DISCONNECT ALL;
}
   Ce code génèrera une erreur comme celle qui suit :
ecpg test_cpp.pgc
test_cpp.pgc:28: ERROR: variable "dbname" is not declared
   
   Pour éviter ce problème de portée, la méthode test
   pourrait être modifiée pour utiliser une variable locale comme stockage
   intermédiaire. Mais cette approche n'est qu'un mauvais contournement,
   parce qu'elle rend le code peu élégant et réduit la performance.
   
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);
}
   
   Si vous comprenez ces limitations techniques du préprocesseur
   ecpg en C++, vous arriverez peut-être à la conclusion
   que lier des objets C et C++ au moment du link pour permettre à des
   applications C++ d'utiliser les fonctionnalités d'ECPG pourrait
   être mieux que d'utiliser des commandes SQL embarquées dans du code
   C++ directement. Cette section décrit un moyen de séparer des commandes
   SQL embarquées du code d'une application C++ à travers un exemple simple.
   Dans cet exemple, l'application est implémentée en C++, alors que
   C et ECPG sont utilisés pour se connecter au serveur PostgreSQL.
  
   Trois types de fichiers devront être créés: un fichier C
   (*.pgc), un fichier d'entête, et un fichier C++ :
   
test_mod.pgc
       Un module de routines pour exécuter des commandes SQL embarquées en C.
       Il sera converti en test_mod.c par le préprocesseur.
       
#include "test_mod.h"
#include <stdio.h>
void
db_connect()
{
    EXEC SQL CONNECT TO testdb1;
    EXEC SQL SELECT pg_catalog.set_config('search_path', '', false); EXEC SQL COMMIT;
}
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
       Un fichier d'entête avec les déclarations des fonctions
       du module C (test_mod.pgc). Il est inclus
       par test_cpp.cpp. Ce fichier devra avoir un
       bloc extern "C" autour des déclarations,
       parce qu'il sera lié à partir d'un module C++.
       
#ifdef __cplusplus
extern "C" {
#endif
void db_connect();
void db_test();
void db_disconnect();
#ifdef __cplusplus
}
#endif
       
test_cpp.cpp
       Le code principal de l'application, incluant
       la routine main, et dans cet exemple
       une classe 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;
}
       
   Pour construire l'application, procédez comme suit. Convertissez
   test_mod.pgc en test_mod.c en
   lançant ecpg, et générez
   test_mod.o en compilant
   test_mod.c avec le compilateur C:
   
ecpg -o test_mod.c test_mod.pgc cc -c test_mod.c -o test_mod.o
   Puis, générez test_cpp.o en compilant
   test_cpp.cpp avec le compilateur C++:
   
c++ -c test_cpp.cpp -o test_cpp.o
   Finalement, liez ces objets, test_cpp.o
   et test_mod.o, dans un exécutable, en utilisant
   le compilateur C++:
   
c++ test_cpp.o test_mod.o -lecpg -o test_cpp