PostgreSQL ECPG ifdef include等预处理用法

2 minute read

背景

PostgreSQL 社区版本的ecpg在一些预处理的用法上和Oracle的PROC有一些不一样的地方,使用者需要注意。

例如社区版本的ecpg不支持c里面使用的#ifdef或者#ifndef这样的预处理语法,需要用其他写法来替代。

所以你如果使用#ifdef这样的写法在.pgc里面,在使用ecpg编译时报错,你可能觉得很奇怪。

例子

$ vi t.pgc  
#include <stdio.h>  
#include <stdlib.h>  
#include <pgtypes_numeric.h>  
  
EXEC SQL WHENEVER SQLERROR STOP;  
  
int  
main(void)  
{  
EXEC SQL BEGIN DECLARE SECTION;  
    numeric *num;  
    numeric *num2;  
    decimal *dec;  
  
#ifdef ABC    // ecpg对于这样的代码会整段拷贝输出到.c,同时里面的所有语句都需要被parser过一遍,因此可能报错  
    errtype *abc;  
#endif  
  
EXEC SQL END DECLARE SECTION;  
  
    EXEC SQL CONNECT TO tcp:postgresql://xxx.xxxcs.com:3433/postgres AS db_digoal USER digoal USING pwd;  
  
    num = PGTYPESnumeric_new();  
    dec = PGTYPESdecimal_new();  
  
    EXEC SQL SELECT 12.345::numeric(4,2), 23.456::decimal(4,2) INTO :num, :dec;  
  
    printf("numeric = %s\n", PGTYPESnumeric_to_asc(num, 0));  
    printf("numeric = %s\n", PGTYPESnumeric_to_asc(num, 1));  
    printf("numeric = %s\n", PGTYPESnumeric_to_asc(num, 2));  
  
    /* Convert decimal to numeric to show a decimal value. */  
    num2 = PGTYPESnumeric_new();  
    PGTYPESnumeric_from_decimal(dec, num2);  
  
    printf("decimal = %s\n", PGTYPESnumeric_to_asc(num2, 0));  
    printf("decimal = %s\n", PGTYPESnumeric_to_asc(num2, 1));  
    printf("decimal = %s\n", PGTYPESnumeric_to_asc(num2, 2));  
  
    PGTYPESnumeric_free(num2);  
    PGTYPESdecimal_free(dec);  
    PGTYPESnumeric_free(num);  
  
    EXEC SQL COMMIT;  
    EXEC SQL DISCONNECT ALL;  
    return 0;  
}  

编译报错

ecpg -t -c -I/home/digoal/pgsql9.6/include -o t.c t.pgc  
t.pgc:16: ERROR: unrecognized data type name "errtype"  

如何修正呢?

#ifdef ABC  
    errtype *abc;  
#endif  

改成

EXEC SQL ifdef ABC;  
    errtype *abc;  
EXEC SQL endif;  

编译通过

digoal@iZ25zysa2jmZ-> ecpg -t -c -I/home/digoal/pgsql9.6/include -o t.c t.pgc  

加上ABC宏,里面的这一段才会过parser。

digoal@iZ25zysa2jmZ-> ecpg -t -c -I/home/digoal/pgsql9.6/include -o t.c -D ABC t.pgc  
t.pgc:16: ERROR: unrecognized data type name "errtype"  

PostgreSQL ecpg还支持include的预处理.

如果include的头文件中包含了ECPG的用法,必须使用以下几种方式来预处理

EXEC SQL INCLUDE filename;  
EXEC SQL INCLUDE <filename>;  
EXEC SQL INCLUDE "filename";  

如果include的文件没有ECPG的语法,则不需要这么做,使用原来的方法即可,ecpg会直接拷贝输出到.c

#include <filename.h>  

对于EDB提供的ecpg版本,是支持#ifdef这种写法的,用于兼容ORACLE的PROC。

参考

https://www.postgresql.org/docs/9.5/static/ecpg-preproc.html

EDB ECPG

https://www.enterprisedb.com/docs/en/9.5/ecpg/Postgres_Plus_Advanced_Server_ecpgPlus_Guide.1.24.html#

The ECPGPlus C-preprocessor enforces two behaviors that are dependent on the mode in which you invoke ECPGPlus:  
•  
PROC mode  
•  
non-PROC mode  
  
Compiling in PROC mode  
In PROC mode, ECPGPlus allows you to:  
•  
Declare host variables outside of an EXEC SQL BEGIN/END DECLARE SECTION.  
•  
Use any C variable as a host variable as long as it is of a data type compatible with ECPG.  
When you invoke ECPGPlus in PROC mode (by including the -C PROC keywords), the ECPG compiler honors the following C-preprocessor directives:  
#include  
#if expression  
#ifdef symbolName  
#ifndef symbolName  
#else  
#elif expression  
#endif  
#define symbolName expansion  
#define symbolName([macro arguments]) expansion  
#undef symbolName  
#defined(symbolName)  
  
Pre-processor directives are used to effect or direct the code that is received by the compiler. For example, using the following code sample:  
#if HAVE_LONG_LONG == 1  
#define BALANCE_TYPE long long  
#else  
#define BALANCE_TYPE double  
#endif  
...  
BALANCE_TYPE customerBalance;  
  
If you invoke ECPGPlus with the following command-line arguments:  
ecpg –C PROC –DHAVE_LONG_LONG=1  
ECPGPlus will copy the entire fragment (without change) to the output file, but will only send the following tokens to the ECPG parser:  
long long customerBalance;  
On the other hand, if you invoke ECPGPlus with the following command-line arguments:  
ecpg –C PROC –DHAVE_LONG_LONG=0  
The ECPG parser will receive the following tokens:  
double customerBalance;  
  
If your code uses preprocessor directives to filter the code that is sent to the compiler, the complete code is retained in the original code, while the ECPG parser sees only the processed token stream.  
  
  
Compiling in non-PROC mode  
If you do not include the -C PROC command-line option:  
•  
C preprocessor directives are copied to the output file without change.  
•  
You must declare the type and name of each C variable that you intend to use as a host variable within an EXEC SQL BEGIN/END DECLARE section.  
When invoked in non-PROC mode, ECPG implements the behavior described in the PostgreSQL Core documentation  

Flag Counter

digoal’s 大量PostgreSQL文章入口