Home Explore Blog CI



postgresql

71th chunk of `doc/src/sgml/ecpg.sgml`
3a30219698c26f78a9ebaa919c41cf6103d8bbddb27f8cd20000000100000fa7
 code written in
   C++ application code that uses complicated features specific to C++
   might fail to be preprocessed correctly or might not work as
   expected.
  </para>

  <para>
   A safe way to use the embedded SQL code in a C++ application is
   hiding the ECPG calls in a C module, which the C++ application code
   calls into to access the database, and linking that together with
   the rest of the C++ code.  See <xref linkend="ecpg-cpp-and-c"/>
   about that.
  </para>

  <sect2 id="ecpg-cpp-scope">
   <title>Scope for Host Variables</title>

   <para>
    The <command>ecpg</command> preprocessor understands the scope of
    variables in C.  In the C language, this is rather simple because
    the scopes of variables is based on their code blocks.  In C++,
    however, the class member variables are referenced in a different
    code block from the declared position, so
    the <command>ecpg</command> preprocessor will not understand the
    scope of the class member variables.
   </para>

   <para>
    For example, in the following case, the <command>ecpg</command>
    preprocessor cannot find any declaration for the
    variable <literal>dbname</literal> in the <literal>test</literal>
    method, so an error will occur.

<programlisting>
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;
}
</programlisting>

    This code will result in an error like this:
<screen>
<userinput>ecpg test_cpp.pgc</userinput>
test_cpp.pgc:28: ERROR: variable "dbname" is not declared
</screen>
   </para>

   <para>
    To avoid this scope issue, the <literal>test</literal> method
    could be modified to use a local variable as intermediate storage.
    But this approach is only a poor workaround, because it uglifies
    the code and reduces performance.

<programlisting>
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);
}
</programlisting>
   </para>
  </sect2>

  <sect2 id="ecpg-cpp-and-c">
   <title>C++ Application Development with External C Module</title>

   <para>
    If you understand these technical limitations of
    the <command>ecpg</command> preprocessor in C++, you might come to
    the conclusion that linking C objects and C++ objects at the link
    stage to enable C++ applications to use ECPG features could be
    better than writing some embedded SQL commands in C++ code
    directly.  This section describes a way to separate some embedded
    SQL commands from C++ application code with a simple example.  In
    this example, the application is implemented in C++, while C and
    ECPG is used to connect to the PostgreSQL server.
   </para>

   <para>
    Three kinds of files have to be created: a C file
    (<filename>*.pgc</filename>), a header file, and a C++ file:

    <variablelist>
     <varlistentry id="ecpg-cpp-and-c-test-mod-pgc">
      <term><filename>test_mod.pgc</filename></term>
      <listitem>
       <para>
        A sub-routine module to execute SQL commands embedded in C.
        It is going to be converted
        into <filename>test_mod.c</filename> by the preprocessor.

<programlisting>
#include "test_mod.h"
#include &lt;stdio.h&gt;

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;

Title: ECPG and C++: Scope Issues and Using External C Modules
Summary
The `ecpg` preprocessor's limitations in handling C++ code, particularly concerning variable scopes within classes, are highlighted. It explains why the preprocessor may fail to recognize class member variables when used in embedded SQL commands within class methods. A workaround involving temporary local variables is presented but deemed unsatisfactory. The document then advocates for a more robust approach: isolating ECPG calls within a separate C module. This allows C++ applications to interact with the database through the C module, mitigating the preprocessor's C++ limitations. The section describes the files needed (C, header, C++) and gives an example.