35.15. Informix 兼容模式

ecpg可以在* Informix 兼容模式*下运行。如果此模式处于活动状态,它将尝试表现为 Informix E/SQL 的 Informix 预编译器。通常来说,这将允许您使用美元符号代替EXEC SQLPrimitives 来引入嵌入式 SQL 命令:

$int j = 3;
$CONNECT TO :dbname;
$CREATE TABLE test(i INT PRIMARY KEY, j INT);
$INSERT INTO test(i, j) VALUES (7, :j);
$COMMIT;

Note

$和后面的预处理程序指令之间没有空格,即includedefineifdef等。否则,预处理程序会将令牌解析为主机变量。

有两种兼容模式:INFORMIXINFORMIX_SE

链接使用此兼容模式的程序时,切记要针对 ECPG 随附的libcompat进行链接。

除了前面解释的语法糖外,Informix 兼容模式还移植了一些用于数据 Importing,输出和转换的功能,以及从 E/SQL 到 ECPG 的嵌入式 SQL 语句。

Informix 兼容性模式与 ECPG 的 pgtypeslib 库紧密相连。 pgtypeslib 将 SQL 数据类型 Map 到 C 主机程序内的数据类型,并且 Informix 兼容模式的大多数附加功能允许您对这些 C 主机程序类型进行操作。但是请注意,兼容性的程度受到限制。它不会尝试复制 Informix 行为;它允许您执行或多或少的相同操作,并为您提供具有相同名称和相同基本行为的功能,但是如果您当前使用的是 Informix,则不能直接替换。此外,某些数据类型是不同的。例如,PostgreSQL 的日期时间和间隔类型不知道诸如YEAR TO MINUTE之类的范围,因此您也不会在 ECPG 中找到对此的支持。

35 .15.1. 附加类型

现在,在 Informix 模式下无需使用typedef即可支持用于存储右修剪的字符串数据的 Informix 特殊“字符串”伪类型。实际上,在 Informix 模式下,ECPG 拒绝处理包含typedef sometype string;的源文件。

EXEC SQL BEGIN DECLARE SECTION;
string userid; /* this variable will contain trimmed data */
EXEC SQL END DECLARE SECTION;

EXEC SQL FETCH MYCUR INTO :userid;

35 .15.2. 附加/缺少嵌入式 SQL 语句

$CLOSE DATABASE;                /* close the current connection */
EXEC SQL CLOSE DATABASE;

35 .15.3. 与 Informix 兼容的 SQLDADescriptors 区域

Informix 兼容模式支持的结构与Section 35.7.2中描述的结构不同。见下文:

struct sqlvar_compat
{
    short   sqltype;
    int     sqllen;
    char   *sqldata;
    short  *sqlind;
    char   *sqlname;
    char   *sqlformat;
    short   sqlitype;
    short   sqlilen;
    char   *sqlidata;
    int     sqlxid;
    char   *sqltypename;
    short   sqltypelen;
    short   sqlownerlen;
    short   sqlsourcetype;
    char   *sqlownername;
    int     sqlsourceid;
    char   *sqlilongdata;
    int     sqlflags;
    void   *sqlreserved;
};

struct sqlda_compat
{
    short  sqld;
    struct sqlvar_compat *sqlvar;
    char   desc_name[19];
    short  desc_occ;
    struct sqlda_compat *desc_next;
    void  *reserved;
};

typedef struct sqlvar_compat    sqlvar_t;
typedef struct sqlda_compat     sqlda_t;

全局属性是:

每个字段的属性如下,它们存储在sqlvar数组中:

int intval;

switch (sqldata->sqlvar[i].sqltype)
{
    case SQLINTEGER:
        intval = *(int *)sqldata->sqlvar[i].sqldata;
        break;
  ...
}
if (*(int2 *)sqldata->sqlvar[i].sqlind != 0)
    printf("value is NULL\n");

Example:

EXEC SQL INCLUDE sqlda.h;

    sqlda_t        *sqlda; /* This doesn't need to be under embedded DECLARE SECTION */

    EXEC SQL BEGIN DECLARE SECTION;
    char *prep_stmt = "select * from table1";
    int i;
    EXEC SQL END DECLARE SECTION;

    ...

    EXEC SQL PREPARE mystmt FROM :prep_stmt;

    EXEC SQL DESCRIBE mystmt INTO sqlda;

    printf("# of fields: %d\n", sqlda->sqld);
    for (i = 0; i < sqlda->sqld; i++)
      printf("field %d: \"%s\"\n", sqlda->sqlvar[i]->sqlname);

    EXEC SQL DECLARE mycursor CURSOR FOR mystmt;
    EXEC SQL OPEN mycursor;
    EXEC SQL WHENEVER NOT FOUND GOTO out;

    while (1)
    {
      EXEC SQL FETCH mycursor USING sqlda;
    }

    EXEC SQL CLOSE mycursor;

    free(sqlda); /* The main structure is all to be free(),
                  * sqlda and sqlda->sqlvar is in one allocated area */

有关更多信息,请参见sqlda.hHeaders 和src/interfaces/ecpg/test/compat_informix/sqlda.pgc回归测试。

35 .15.4. 附加功能

int decadd(decimal *arg1, decimal *arg2, decimal *sum);

该函数接收一个指向十进制类型(arg1)的第一个操作数的指针,一个指向十进制类型(arg2)的第二个操作数的指针和一个将包含和(sum)的十进制类型的值的指针。成功时,函数返回 0.如果发生溢出,则返回ECPG_INFORMIX_NUM_OVERFLOW;如果发生下溢,则返回ECPG_INFORMIX_NUM_UNDERFLOW。对于其他失败,返回-1,并将errno设置为 pgtypeslib 的相应errno号。

int deccmp(decimal *arg1, decimal *arg2);

该函数接收一个指向第一个十进制值(arg1)的指针,一个指向第二个十进制值(arg2)的指针,并返回一个整数值,该整数值指示较大的值。

void deccopy(decimal *src, decimal *target);

该函数接收指向十进制值的指针,该指针应被复制为第一个参数(src),并指向十进制类型的目标结构(target)作为第二个参数。

int deccvasc(char *cp, int len, decimal *np);

该函数接收一个指向字符串的指针,该指针包含要转换的数字的字符串表示形式(cp)及其长度lennp是保存操作结果的十进制值的指针。

有效格式例如:-2.794+3.44592.49E07-32.84e-4

该函数成功返回 0.如果发生上溢或下溢,则返回ECPG_INFORMIX_NUM_OVERFLOWECPG_INFORMIX_NUM_UNDERFLOW。如果无法解析 ASCII 表示形式,则返回ECPG_INFORMIX_BAD_NUMERIC;如果解析指数时发生此问题,则返回ECPG_INFORMIX_BAD_EXPONENT

int deccvdbl(double dbl, decimal *np);

该函数接收应将 double 类型的变量转换为其第一个参数(dbl)。作为第二个参数(np),该函数接收一个指向十进制变量的指针,该指针应保存操作的结果。

如果成功,函数将返回 0,如果转换失败,则返回负值。

int deccvint(int in, decimal *np);

该函数接收应转换为 int 类型的变量作为其第一个参数(in)。作为第二个参数(np),该函数接收一个指向十进制变量的指针,该指针应保存操作的结果。

如果成功,函数将返回 0,如果转换失败,则返回负值。

int deccvlong(long lng, decimal *np);

该函数接收 long 类型的变量,该变量应转换为其第一个参数(lng)。作为第二个参数(np),该函数接收一个指向十进制变量的指针,该指针应保存操作的结果。

如果成功,函数将返回 0,如果转换失败,则返回负值。

int decdiv(decimal *n1, decimal *n2, decimal *result);

该函数接收指向第一个(n1)和第二个(n2)操作数的变量的指针,并计算n1/n2result是指向应该保存操作结果的变量的指针。

成功时,返回 0,如果除法失败,则返回负值。如果发生上溢或下溢,该函数将分别返回ECPG_INFORMIX_NUM_OVERFLOWECPG_INFORMIX_NUM_UNDERFLOW。如果发现尝试除以零,则该函数返回ECPG_INFORMIX_DIVIDE_ZERO

int decmul(decimal *n1, decimal *n2, decimal *result);

该函数接收指向第一个(n1)和第二个(n2)操作数的变量的指针,并计算n1 * n2result是指向应该保存操作结果的变量的指针。

成功时,返回 0,如果乘法失败,则返回负值。如果发生上溢或下溢,该函数将分别返回ECPG_INFORMIX_NUM_OVERFLOWECPG_INFORMIX_NUM_UNDERFLOW

int decsub(decimal *n1, decimal *n2, decimal *result);

该函数接收指向第一个(n1)和第二个(n2)操作数的变量的指针,并计算n1-n2result是指向应该保存操作结果的变量的指针。

成功时,返回 0,如果减法失败,则返回负值。如果发生上溢或下溢,该函数将分别返回ECPG_INFORMIX_NUM_OVERFLOWECPG_INFORMIX_NUM_UNDERFLOW

int dectoasc(decimal *np, char *cp, int len, int right)

该函数接收一个指向十进制(np)类型的变量的指针,该变量将转换为其文本表示形式。 cp是应该保存操作结果的缓冲区。参数right指定输出中应包含小数点右边的几位数。结果将四舍五入到此十进制数字。将right设置为-1 表示输出中应包含所有可用的十进制数字。如果用len表示的输出缓冲区的长度不足以容纳包含尾随零字节的文本表示形式,则结果中仅存储一个*字符,并返回-1.

如果缓冲区cp太小,则函数返回-1;如果内存已耗尽,则返回ECPG_INFORMIX_OUT_OF_MEMORY

int dectodbl(decimal *np, double *dblp);

该函数接收指向要转换的十进制值的指针(np)和指向应保存运算结果的 double 变量的指针(dblp)。

成功时,返回 0,如果转换失败,则返回负值。

int dectoint(decimal *np, int *ip);

该函数接收一个指向要转换的十进制值的指针(np)和一个指向应该包含运算结果的整数变量(ip)的指针。

成功时,返回 0,如果转换失败,则返回负值。如果发生溢出,则返回ECPG_INFORMIX_NUM_OVERFLOW

请注意,ECPG 实现与 Informix 实现不同。 Informix 将整数限制为-32767 到 32767,而 ECPG 实现中的限制取决于体系结构(-INT_MAX .. INT_MAX)。

int dectolong(decimal *np, long *lngp);

该函数接收一个指向要转换的十进制值的指针(np)和一个指向应保存运算结果的 long 变量的指针(lngp)。

成功时,返回 0,如果转换失败,则返回负值。如果发生溢出,则返回ECPG_INFORMIX_NUM_OVERFLOW

请注意,ECPG 实现与 Informix 实现不同。 Informix 将一个长整数限制为-2,147,483,647 到 2,147,483,647,而 ECPG 实现中的限制取决于体系结构(-LONG_MAX .. LONG_MAX)。

int rdatestr(date d, char *str);

该函数接收两个参数,第一个是转换日期(d),第二个是指向目标字符串的指针。输出格式始终为yyyy-mm-dd,因此您需要为字符串分配至少 11 个字节(包括零字节终止符)。

如果成功,该函数将返回 0,如果出错则返回负值。

请注意,ECPG 的实现不同于 Informix 的实现。在 Informix 中,格式可以受到设置环境变量的影响。但是,在 ECPG 中,您无法更改输出格式。

int rstrdate(char *str, date *d);

该函数接收要转换的日期的文本表示形式(str)和指向日期类型的变量(d)的指针。此功能不允许您指定格式掩码。它使用 Informix 的默认格式掩码mm/dd/yyyy。在内部,此功能是通过rdefmtdate实现的。因此,rstrdate并不快,如果您有选择,则应该选择rdefmtdate,这样可以显式指定格式掩码。

该函数返回与rdefmtdate相同的值。

void rtoday(date *d);

该函数接收指向其设置为当前日期的日期变量(d)的指针。

在内部,此函数使用PGTYPESdate_today函数。

int rjulmdy(date d, short mdy[3]);

该函数接收日期d和指向 3 个短整数值mdy的数组的指针。变量名称指示 Sequences:mdy[0]将设置为包含月份的数字,mdy[1]将被设置为 day 的值,mdy[2]将包含年份。

该函数此刻始终返回 0.

该函数在内部使用PGTYPESdate_julmdy函数。

int rdefmtdate(date *d, char *fmt, char *str);

该函数接收一个指向日期值的指针,该日期值应保存操作的结果(d),用于解析日期的格式掩码(fmt)和包含日期的文本表示形式的 C char *字符串(str)。文本表示应与格式掩码匹配。但是,您无需将字符串与格式掩码进行 1:1Map。该函数仅分析 Sequences,并寻找表示年份位置的 Literalsyyyyyymm指示月份的位置和dd指示日期的位置。

该函数返回以下值:

在内部,此函数被实现为使用PGTYPESdate_defmt_asc函数。请参阅参考资料中的示例 Importing 表。

int rfmtdate(date d, char *fmt, char *str);

该函数接收要转换的日期(d),格式掩码(fmt)和用于保存日期文本表示的字符串(str)。

成功时,返回 0,如果发生错误,则返回负值。

在内部,此函数使用PGTYPESdate_fmt_asc函数,有关示例,请参见参考。

int rmdyjul(short mdy[3], date *d);

该函数接收 3 个短整数(mdy)的数组和一个指向应保存操作结果的 date 类型的变量的指针。

当前,该函数始终返回 0.

在内部将函数实现为使用函数PGTYPESdate_mdyjul

int rdayofweek(date d);

该函数接收日期变量d作为其唯一参数,并返回一个整数,该整数指示该日期的星期几。

在内部将函数实现为使用函数PGTYPESdate_dayofweek

void dtcurrent(timestamp *ts);

该函数检索当前时间戳并将其保存到ts指向的时间戳变量中。

int dtcvasc(char *str, timestamp *ts);

该函数接收要解析的字符串(str)和指向应该保存操作结果(ts)的 timestamp 变量的指针。

如果成功,该函数将返回 0,如果出错则返回负值。

在内部,此函数使用PGTYPEStimestamp_from_asc函数。有关 Importing 示例的表格,请参见此处的参考。

dtcvfmtasc(char *inbuf, char *fmtstr, timestamp *dtvalue)

该函数接收要解析的字符串(inbuf),要使用的格式掩码(fmtstr)和指向应该保存操作结果的 timestamp 变量的指针(dtvalue)。

此功能是通过PGTYPEStimestamp_defmt_asc功能实现的。有关可以使用的格式说明符的列表,请参见此处的文档。

如果成功,该函数将返回 0,如果出错则返回负值。

int dtsub(timestamp *ts1, timestamp *ts2, interval *iv);

该函数将从ts1指向的 timestamp 变量中减去ts2指向的 timestamp 变量,并将结果存储在iv指向的 interval 变量中。

成功后,函数将返回 0,如果发生错误,则返回负值。

int dttoasc(timestamp *ts, char *output);

该函数接收指向要转换的时间戳变量的指针(ts)和应保存操作结果的字符串(output)。它将根据 SQL 标准YYYY-MM-DD HH:MM:SSts转换为其文本表示形式。

成功后,函数将返回 0,如果发生错误,则返回负值。

int dttofmtasc(timestamp *ts, char *output, int str_len, char *fmtstr);

该函数接收指向时间戳的指针以将其转换为第一个参数(ts),指向输出缓冲区(output)的指针,已分配给输出缓冲区的最大长度(str_len)和用于该缓冲区的格式掩码转换(fmtstr)。

成功后,函数将返回 0,如果发生错误,则返回负值。

在内部,此函数使用PGTYPEStimestamp_fmt_asc函数。有关可以使用哪种格式掩码说明符的信息,请参见那里的参考。

int intoasc(interval *i, char *str);

该函数接收一个指向要转换的时间间隔变量的指针(i)和应保存该运算结果的字符串(str)。它将根据 SQL 标准YYYY-MM-DD HH:MM:SSi转换为其文本表示形式。

成功后,函数将返回 0,如果发生错误,则返回负值。

int rfmtlong(long lng_val, char *fmt, char *outbuf);

该函数接收长值lng_val,格式掩码fmt和指向输出缓冲区outbuf的指针。它将根据格式掩码将 long 值转换为其文本表示形式。

格式掩码可以由以下格式指定字符组成:

void rupshift(char *str);

该函数接收指向该字符串的指针,并将每个小写字母转换为大写字母。

int byleng(char *str, int len);

该函数期望将固定长度的字符串作为其第一个参数(str),并将其长度作为其第二个参数(len)。它返回有效字符的数量,即不带空格的字符串的长度。

void ldchar(char *src, int len, char *dest);

该函数接收要复制的定长字符串(src),其长度(len)和指向目标内存的指针(dest)。请注意,您需要为dest指向的字符串保留至少len+1个字节。该函数最多将len个字节复制到新位置(如果源字符串末尾有空格,则将其复制),并添加空终止符。

int rgetmsg(int msgnum, char *s, int maxsize);

此功能存在,但目前尚未实现!

int rtypalign(int offset, int type);

此功能存在,但目前尚未实现!

int rtypmsize(int type, int len);

此功能存在,但目前尚未实现!

int rtypwidth(int sqltype, int sqllen);

此功能存在,但目前尚未实现!

int rsetnull(int t, char *ptr);

该函数接收一个指示变量类型的整数,以及一个指向变量本身的指针,该指针被强制转换为 C char *指针。

存在以下类型:

这是对此函数的调用示例:

$char c[] = "abc       ";
$short s = 17;
$int i = -74874;

rsetnull(CCHARTYPE, (char *) c);
rsetnull(CSHORTTYPE, (char *) &s);
rsetnull(CINTTYPE, (char *) &i);
int risnull(int t, char *ptr);

该函数接收要测试的变量的类型(t)以及指向该变量的指针(ptr)。请注意,后者需要转换为 char *。有关可能的变量类型的列表,请参见函数rsetnull

这是如何使用此功能的示例:

$char c[] = "abc       ";
$short s = 17;
$int i = -74874;

risnull(CCHARTYPE, (char *) c);
risnull(CSHORTTYPE, (char *) &s);
risnull(CINTTYPE, (char *) &i);

35 .15.5. 附加常数

请注意,此处所有常量均描述错误,并且所有常量均定义为代表负值。在不同常量的描述中,您还可以找到常量在当前实现中表示的值。但是,您不应依赖此数字。但是,您可以依靠以下事实:它们都定义为代表负值。

上一章 首页 下一章