跳至主要內容

KlustronDB大约 22 分钟

36.15. Informix兼容模式

36.15.1. 附加类型

36.15.2. 附加的/缺少的 嵌入式 SQL 语句

36.15.3. Informix-兼容的 SQLDA 描述符区域

36.15.4. 附加函数

36.15.5. 额外的常量

ecpg可以运行在一种所谓的Informix 兼容模式中。如果这种模式被激活,它的行为就好像它是一个用于Informix E/SQL 的Informix预编译器。一般而言,这将允许你使用美元符号替代EXEC SQL来引入嵌入式 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;

注意

$之间不能有任何空白以及下列之一的预处理器指令:includedefineifdef等。否则,预处理器将把记号解析成一个主变量。

有两种兼容性模式:INFORMIXINFORMIX_SE

在链接使用这种兼容性模式的程序时,要记得链接上和 ECPG 一起发布的libcompat

除了之前解释过的语法糖,Informix兼容性模式从 E/SQL 中移植了一些用于输入、输出和数据转换的函数以及嵌入式 SQL 语句到 ECPG 中。

Informix兼容性模式与 ECPG 的 pgtypeslib 库紧密连接。pgtypeslib 把 SQL 数据类型映射到 C 主程序中的数据类型并且大部分Informix兼容性模式的附加函数允许我们在那些 C 主程序类型上操作。不过注意兼容性的范围被有所限制。它并不是想尝试复制Informix的行为。它允许你做或多或少的相同操作并且给你具有相同名称和相同基本行为的函数,但是此刻如果你使用Informix,其中并没有唾手可得的替代品。此外,一些数据类型也不同。例如,PostgreSQL的日期时间和区间类型不理解范围(例如YEAR TO MINUTE),因此你也无法在 ECPG 中找到支持。

36.15.1. 附加类型

用于存储右切边字符串数据的 Informix-特殊的 "string" 伪类型现在在 Informix 模式中不用typedef就能支持。事实上,在 Informix 模式中,ECPG 拒绝处理包含typedef sometype string;的源文件。

EXEC SQL BEGIN DECLARE SECTION;
string userid; /* 这个变量将包含切边过的数据 */
EXEC SQL END DECLARE SECTION;

EXEC SQL FETCH MYCUR INTO :userid;

36.15.2. 附加的/缺少的 嵌入式 SQL 语句

CLOSE DATABASE : 这个语句关闭当前连接。事实上,这是 ECPG 的DISCONNECT CURRENT语句的同义词:

```programlisting
$CLOSE DATABASE;                /* 关闭当前连接 */
EXEC SQL CLOSE DATABASE;
```

FREE cursor_name : 由于 ECPG 和 Informix ESQL/C 在工作方式上的区别(一个是纯语法转换而另一个依赖于底层的运行时库),在 ECPG 中没有FREE cursor_name语句。这是因为在 ECPG 中,DECLARE CURSOR不会翻译成一个运行时库中使用游标名的函数调用。这意味着在 ECPG 运行时库中不会有 SQL 游标的运行时登记,SQL 游标只登记在 PostgreSQL 服务器中。

FREE statement_name : FREE statement_nameDEALLOCATE PREPARE statement_name的同义词。

36.15.3. Informix-兼容的 SQLDA 描述符区域

Informix-兼容模式支持一种与第 36.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;

全局属性是:

sqld : SQLDA描述符中域的数量。

sqlvar : 每一个域属性的指针。

desc_name : 未使用,用零字节填充。

desc_occ : 已分配结构的尺寸。

desc_next : 如果结果集包含多于一个记录,这个域是下一个 SQLDA 结构的指针。

reserved : 未使用的指针,包含 NULL。为 Informix-兼容性而保留。

对每一个域的属性如下,它们被存储在sqlvar数组中:

sqltype : 域的类型。可以使用的常量定义在sqltypes.h中。

sqllen : 域数据的长度。

sqldata : 域数据的指针。该指针是char *类型,它所指向的数据是二进制个事。例子:

```programlisting
int intval;

switch (sqldata->sqlvar[i].sqltype)
{
    case SQLINTEGER:
        intval = *(int *)sqldata->sqlvar[i].sqldata;
        break;
  ...
}
```

sqlind : NULL 指示符的指针。如果是由 DESCRIBE 或 FETCH 返回,那么它总是一个有效的指针。如果被用作EXECUTE ... USING sqlda;的输入,那么 NULL-指针值意味着这个域的值是非-NULL 的。否则必须正确地设置一个有效的指针和sqlitype。例子:

```programlisting
if (*(int2 *)sqldata->sqlvar[i].sqlind != 0)
    printf("value is NULL\n");
```

sqlname : 域的名称。以 0 终止的字符串。

sqlformat : 在 Informix 中保留,是该域的PQfformat()的值。

sqlitype : NULL 指示符数据的类型。当从服务器返回数据时,它总是 SQLSMINT。当SQLDA被用于一个参数化查询时,数据要根据设置的类型对待。

sqlilen : NULL 指示符数据的长度。

sqlxid : 该域的扩展类型,PQftype()的结果。

sqltypename sqltypelen sqlownerlen sqlsourcetype sqlownername sqlsourceid sqlflags sqlreserved : 未使用。

sqlilongdata : 如果sqllen大于 32kB,它等于sqldata

例子:

EXEC SQL INCLUDE sqlda.h;

    sqlda_t        *sqlda; /* 这不需要在嵌入式 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); /* 主结构完全被 free(),sqlda 和 sqlda->sqlvar 在一个已分配区域中 */

更多信息可见sqlda.h头部和src/interfaces/ecpg/test/compat_informix/sqlda.pgc回归测试。

36.15.4. 附加函数

decadd : 将两个decimal类型值相加。

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

该函数接收第一个类型为 decimal 的操作数的指针(`arg1`)、第二个类型为 decimal 的操作数的指针(`arg2`)以及将包含和的 decimal 值的指针(`sum`)。成功时该函数返回 0。溢出时返回`ECPG_INFORMIX_NUM_OVERFLOW`,下溢时返回`ECPG_INFORMIX_NUM_UNDERFLOW`。其他失败会返回 -1 并且`errno`会被设置为相应的 pgtypeslib 中的`errno`编号。

deccmp : 比较两个 decimal 变量。

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

该函数接收第一个 decimal 值的指针(`arg1`)、第二个 decimal 值的指针(`arg2`)并且返回一个整数值说明哪一个值更大。

* 1,如果`arg1`指向的值大于`var2`指向的值
* -1,如果`arg1`指向的值小于`var2`指向的值
* 0,如果`arg1`指向的值与`arg2`指向的值相等

deccopy : 拷贝一个 decimal 值。

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

该函数接收要拷贝的 decimal 值的指针作为第一个参数(`src`)以及一个类型为 decimal 的目标结构的指针作为第二个参数(`target`)。

deccvasc : 把一个值从 ASCII 表达转换成一个 decimal 类型。

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

该函数接收一个包含要转换的数字的字符串表达的字符串指针(`cp`)及其长度(`len`)。`np`是一个用来保存操作结果的 decimal 值的指针。

例如,可用的格式有:
`-2`、
`.794`、
`+3.44`、
`592.49E07`或者
`-32.84e-4`。

成功时该函数返回 0。如果发生溢出或者下溢,分别返回
`ECPG_INFORMIX_NUM_OVERFLOW`或者
`ECPG_INFORMIX_NUM_UNDERFLOW`。如果 ASCII 表达无法被解析,将返回`ECPG_INFORMIX_BAD_NUMERIC`。如果解析指数时发生问题则返回`ECPG_INFORMIX_BAD_EXPONENT`。

deccvdbl : 将一个 double 值转换成一个 decimal 值。

```synopsis
int deccvdbl(double dbl, decimal *np);
```

该函数接收要被转换的 double 变量作为第一个参数(`dbl`)。该函数接收一个 decimal 变量的指针作为第二个参数(`np`),它被用来保存操作的结果。

该函数在成功时返回 0,在转换失败时返回一个负值。

deccvint : 将一个 int 值转换成 decimal 值。

```synopsis
int deccvint(int in, decimal *np);
```

该函数接收要被转换的 int 变量作为第一个参数(`in`)。该函数接收一个 decimal 变量的指针作为第二个参数(`np`),它被用来保存操作的结果。

该函数在成功时返回 0,在转换失败时返回一个负值。

deccvlong : 将一个 long 值转换成 decimal 值。

```synopsis
int deccvlong(long lng, decimal *np);
```

该函数接收要被转换的 long 变量作为第一个参数(`lng`)。该函数接收一个 decimal 变量的指针作为第二个参数(`np`),它被用来保存操作的结果。

该函数在成功时返回 0,在转换失败时返回一个负值。

decdiv : 用两个 decimal 类型的变量做除法。

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

该函数接收两个变量的指针作为第一个(`n1`)和第二个(`n2`)操作数并且结算`n1`/`n2`。 `result`是一个指向保存操作结果的变量的指针。

成功时返回 0,如果除法失败则返回一个负值。如果发生溢出或下溢,该函数分别返回
`ECPG_INFORMIX_NUM_OVERFLOW`或者
`ECPG_INFORMIX_NUM_UNDERFLOW`。如果发现一次除零尝试,该函数返回
`ECPG_INFORMIX_DIVIDE_ZERO`。

decmul : 将两个 decimal 值相乘。

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

该函数接收两个变量的指针作为第一个(`n1`)和第二个(`n2`)操作数并且结算`n1`*`n2`。 `result`是一个指向保存操作结果的变量的指针。

成功时返回 0,如果乘法失败则返回一个负值。如果发生溢出或下溢,该函数分别返回
`ECPG_INFORMIX_NUM_OVERFLOW`或者
`ECPG_INFORMIX_NUM_UNDERFLOW`。

decsub : 从一个 decimal 值中减去另一个。

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

该函数接收两个变量的指针作为第一个(`n1`)和第二个(`n2`)操作数并且结算`n1`-`n2`。 `result`是一个指向保存操作结果的变量的指针。

成功时返回 0,如果减法失败则返回一个负值。如果发生溢出或下溢,该函数分别返回
`ECPG_INFORMIX_NUM_OVERFLOW`或者
`ECPG_INFORMIX_NUM_UNDERFLOW`。

dectoasc : 将一个 decimal 变量转换成它的 ASCII 表达放在一个 C char* 字符串中。

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

该函数接收一个要被转换成文本表达的 decimal 类型变量的指针(`np`)。`cp`是应保存操作结果的缓冲区。参数`right`指定小数点右边应该有多少位保留在输出中。结果将被圆整到所指定数量的十进制位。将`right`设置为 -1 表示输出中应该包括所有可用的十进制位。如果输出缓冲区的长度(由`len`指定)不足以保存包含拖尾零字节的文本表达,结果中将只保存一个单一的`*`字符并且返回 -1。

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

dectodbl : 将一个 decimal 类型变量转换成一个 double 类型变量。

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

该函数接收一个要转换的 decimal 值的指针(`np`)以及一个保存操作结果的 double 变量的指针(`dblp`)。

该函数在成功时返回 0,在转换失败时返回一个负值。

dectoint : 将一个 decimal 类型变量转换成一个整数类型变量。

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

该函数接收一个要转换的 decimal 值的指针(`np`)以及一个保存操作结果的整数变量的指针(`ip`)。

该函数在成功时返回 0,在转换失败时返回一个负值。如果发生溢出,会返回`ECPG_INFORMIX_NUM_OVERFLOW`。

注意 ECPG 实现与Informix实现不同。Informix限制一个整数的范围是从 -32767 到 32767,而 ECPG 实现中的限制取决于架构(`-INT_MAX .. INT_MAX`)。

dectolong : 将一个 decimal 类型变量转换成一个长整型变量。

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

该函数接收一个要转换的 decimal 值的指针(`np`)以及一个保存操作结果的长整型变量的指针(`lngp`)。

该函数在成功时返回 0,在转换失败时返回一个负值。如果发生溢出,会返回`ECPG_INFORMIX_NUM_OVERFLOW`。

注意 ECPG 实现与Informix实现不同。Informix限制一个整数的范围是从 -2,147,483,647 到 2,147,483,647,而 ECPG 实现中的限制取决于架构(`-LONG_MAX .. LONG_MAX`)。

rdatestr : 将一个日期转换成一个 C char* 字符串。

```synopsis
int rdatestr(date d, char *str);
```

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

成功时该函数返回 0,如果发生错误则返回一个负值。

注意 ECPG 实现与Informix实现不同。在Informix中,该格式可能受到环境变量设置的影响。而在 ECPG 中,你不能改变输出格式。

rstrdate : 解析一个日期的文本表达。

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

该函数接收要转换的日期的文本表达(`str`)以及一个日期类型变量的指针(`d`)。这个函数不允许你指定一个格式掩码。它使用Informix的默认格式掩码`mm/dd/yyyy`。在内部,这个函数用`rdefmtdate`的方式实现。因此,`rstrdate`不会更快,并且如果可以选择,你应该选用允许你显式指定格式掩码的`rdefmtdate`。

该返回与`rdefmtdate`相同的值。

rtoday : 得到当前日期。

```synopsis
void rtoday(date *d);
```

该函数接收一个日期变量的指针(`d`),它会把该变量设置为当前日期。

在内部这个函数使用[`PGTYPESdate_today`](ecpg-pgtypes.md#PGTYPESDATETODAY)函数。

rjulmdy : 从一个日期类型变量中抽取日、月、年的值。

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

该函数接收日期`d`和由 3 个短整型值构成的数组的指针`mdy`。该变量名指定了顺序:`mdy[0]`将被设置为包含月的编号,`mdy[1]`将被设置为日的值,而`mdy[2]`将包含年。

当前该函数总是返回 0。

在内部该函数使用[`PGTYPESdate_julmdy`](ecpg-pgtypes.md#PGTYPESDATEJULMDY)函数。

rdefmtdate : 使用一个格式掩码把一个字符串转换成一个日期类型的值。

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

该函数接收一个用于保存操作结果的日期值的指针(`d`)、要用来解析日期的格式掩码(`fmt`)以及包含日期文本表达的 C char* 字符串(`str`)。该文本表达应该匹配格式掩码。不过,你不需要具有从该字符串到格式掩码的 一一映射。该函数将分析顺序并且寻找表示年的位置的文字`yy`或`yyyy`、表示月的位置的`mm`以及表示日的位置的`dd`。

该函数返回下列值:

* 0 - 该函数成功终止。
* `ECPG_INFORMIX_ENOSHORTDATE` - 该日期不包含日、月、年之间的定界符。在这种情况下,输入字符串必须是正好 6 个或 8 个字节,但实际上却不是。
* `ECPG_INFORMIX_ENOTDMY` - 格式字符串没有正确地指示年、月、日的顺序。
* `ECPG_INFORMIX_BAD_DAY` - 输入字符串不含一个合法的日。
* `ECPG_INFORMIX_BAD_MONTH` - 输入字符串不含一个合法的月。
* `ECPG_INFORMIX_BAD_YEAR` - 输入字符串不含一个合法的年。

在内部这个函数被实现为使用[`PGTYPESdate_defmt_asc`](ecpg-pgtypes.md#PGTYPESDATEDEFMTASC)函数。示例输入表可以在那里找到。

rfmtdate : 使用一个格式掩码将一个日期类型变量转换成它的文本表达。

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

该函数接收要转换的日期(`d`)、格式掩码(`fmt`)以及将保存日期的文本表达的字符串(`str`)。

成功时该函数返回 0,如果发生错误则返回一个负值。

在内部这个函数使用[`PGTYPESdate_fmt_asc`](ecpg-pgtypes.md#PGTYPESDATEFMTASC)函数,例子请参考该函数。

rmdyjul : 从由 3 个短整型组成的数组创建一个日期值,它指定了该日期的日、月、年。

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

该函数接收一个由 3 个短整型构成的数组(`mdy`)以及一个用来保存操作结构的日期类型变量的指针。

当前该函数总是返回 0。

在内部这个函数被实现为使用[`PGTYPESdate_mdyjul`](ecpg-pgtypes.md#PGTYPESDATEMDYJUL)。

rdayofweek : 为一个日期值返回一个表示它是星期几的数字。

```synopsis
int rdayofweek(date d);
```

该函数接收日期变量`d`作为它的唯一参数并且返回一个整数指示这一天是星期几。

* 0 - 周日
* 1 - 周一
* 2 - 周二
* 3 - 周三
* 4 - 周四
* 5 - 周五
* 6 - 周六

在内部这个函数被实现为使用函数[`PGTYPESdate_dayofweek`](ecpg-pgtypes.md#PGTYPESDATEDAYOFWEEK)。

dtcurrent : 检索当前的时间戳。

```synopsis
void dtcurrent(timestamp *ts);
```

该函数检索当前时间戳并且把它保存在`ts`指向的时间戳变量中。

dtcvasc : 把一个时间戳从它的文本表达解析到一个时间戳变量中。

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

该函数接收要解析的字符串(`str`)以及一个指向保存操作结果的时间戳变量的指针(`ts`)。

成功时该函数返回 0,如果发生错误则返回一个负值。

在内部这个函数使用[`PGTYPEStimestamp_from_asc`](ecpg-pgtypes.md#PGTYPESTIMESTAMPFROMASC)函数。一个输入示例的表格可以参考该函数的文档。

dtcvfmtasc : 使用一个格式掩码把一个时间戳从它的文本表达解析到一个时间戳变量中。

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

该函数接收要解析的字符串(`inbuf`)、要使用的格式掩码(`fmtstr`)以及一个指向保存操作结果的时间戳变量的指针(`dtvalue`)。

这个函数通过[`PGTYPEStimestamp_defmt_asc`](ecpg-pgtypes.md#PGTYPESTIMESTAMPDEFMTASC)函数实现。可以使用的格式说明符的列表可以参考该函数的文档。

成功时该函数返回 0,如果发生错误则返回一个负值。

dtsub : 从一个时间戳中减去另一个并且返回一个区间类型变量。

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

该函数将从`ts1`指向的时间戳变量中减去`ts2`指向的时间戳变量,并且将把结果存储在`iv`指向的区间变量中。

成功时该函数返回 0,如果发生错误则返回一个负值。

dttoasc : 将一个时间戳变量转换成一个 C char* 字符串。

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

该函数接收一个要转换的时间戳变量的指针(`ts`)以及用于保存操作结果的字符串(`output`)。它根据 SQL 标准把`ts`转换成它的文本表达,形式为`YYYY-MM-DD HH:MM:SS`。

成功时该函数返回 0,如果发生错误则返回一个负值。

dttofmtasc : 使用一个格式掩码将一个时间戳变量转换成一个 C char*。

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

该函数接收一个要转换的时间戳的指针(`ts`)、一个输出缓冲区的指针(`output`)、已经为输出缓冲区分配的最大长度(`str_len`)以及用于转换的格式掩码(`fmtstr`)。

成功时该函数返回 0,如果发生错误则返回一个负值。

在内部,这个函数使用[`PGTYPEStimestamp_fmt_asc`](ecpg-pgtypes.md#PGTYPESTIMESTAMPFMTASC)函数。可以使用的格式说明符的列表可以参考该函数的文档。

intoasc : 将一个区间变量转换成一个 C char* 字符串。

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

该函数接收一个要转换的区间变量的指针(`i`)以及要保持该操作结果的字符串(`str`)。它根据 SQL 标准把`i`转换成它的文本表达,形式为`YYYY-MM-DD HH:MM:SS`。

成功时该函数返回 0,如果发生错误则返回一个负值。

rfmtlong : 用一个格式掩码将一个长整型值转换成它的文本表达。

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

该函数接收长整型值`lng_val`、格式掩码`fmt`以及输出缓冲区的指针`outbuf`。它根据格式掩码将长整型值转换成文本表达。

格式掩码可以由下列格式说明字符构成:

* `*` (星) - 如果这个位置可以为空白,否则用一个星号填充。
* `&` (花号) -如果这个位置可以为空白,否则用一个零填充。
* `#` - 把前导零转变成空白。
* `<` - 左对齐字符串中的数字。
* `,` (逗号) - 将有四个或者更多数位的数字份组成用逗号分隔的 3 数位组。
* `.` (点) - 这个字符分隔数字的整数部分和小数部分。
* `-` (负) - 如果该数字是一个负值则负号会出现。
* `+` (加) - 如果该数字是一个正值则加号会出现。
* `(` - 这会替换负数前面的负号。负号将不会出现。
* `)` - 这个字符替换负号并且被打印在负值的后面。
* `$` - 货币符号。

rupshift : 把一个字符串转换成大写形式。

```synopsis
void rupshift(char *str);
```

该函数接收一个字符串的指针并且把每一个小写形式的字符变成大写形式。

byleng : 返回一个字符串的字符数,其中不含拖尾的空白。

```synopsis
int byleng(char *str, int len);
```

该函数期待一个定长字符串作为它的第一个参数(`str`)并且把它的长度作为第二个参数(`len`)。该函数会返回有效字符的数量,也就是字符串不含拖尾空白的长度。

ldchar : 复制一个定长字符串到一个空终止的字符串。

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

该函数接收要被复制的定长字符串(`src`)、它的长度(`len`)以及目标内存的指针(`dest`)。注意你需要为`dest`指向的字符串保留至少`len+1`个字节。该函数复制至多`len`个字节到新的位置(如果源字符串有拖尾的空格)并且增加空终止符。

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

这个函数存在,但是目前还没有实现!

rtypalign : synopsis int rtypalign(int offset, int type);

这个函数存在,但是目前还没有实现!

rtypmsize : synopsis int rtypmsize(int type, int len);

这个函数存在,但是目前还没有实现!

rtypwidth : synopsis int rtypwidth(int sqltype, int sqllen);

这个函数存在,但是目前还没有实现!

rsetnull : 设置一个变量为 NULL。

```synopsis
int rsetnull(int t, char *ptr);
```

该函数接收一个表示变量类型的整数以及一个被造型成 C char* 指针的变量本身的指针。

存在下列类型:

* `CCHARTYPE` - 用于类型`char`或者`char*`的一个变量
* `CSHORTTYPE` - 用于类型`short int`的一个变量
* `CINTTYPE` - 用于类型`int`的一个变量
* `CBOOLTYPE` - 用于类型`boolean`的一个变量
* `CFLOATTYPE` - 用于类型`float`的一个变量
* `CLONGTYPE` - 用于类型`long`的一个变量
* `CDOUBLETYPE` - 用于类型`double`的一个变量
* `CDECIMALTYPE` - 用于类型`decimal`的一个变量
* `CDATETYPE` - 用于类型`date`的一个变量
* `CDTIMETYPE` - 用于类型`timestamp`的一个变量

这里是一个调用这个函数的例子:

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

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

risnull : 测试一个变量是否为 NULL。

```synopsis
int risnull(int t, char *ptr);
```

该函数接收要测试的变量的类型(`t`)以及一个指向该变量的指针(`ptr`)。注意后者需要被造型为一个 char*。可能的变量类型请见函数[`rsetnull`](ecpg-informix-compat.md#RSETNULL)。

这里是一个如何使用这个函数的例子:

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

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

36.15.5. 额外的常量

注意这里所有的常量都描述错误并且它们都被定义为表示负值。在每一种不同常量的描述中,你还可以找到在当前实现中该常量表示的值。不过你不应该依赖于这个数字。但是你可以相信所有的这些常量都是被定义为表示负值。

ECPG_INFORMIX_NUM_OVERFLOW : 如果在一次计算中发生了溢出,函数会返回这个值。在内部它被定义为 -1200(Informix定义)。

ECPG_INFORMIX_NUM_UNDERFLOW : 如果在一次计算中发生了下溢,函数会返回这个值。在内部它被定义为 -1201(Informix定义)。

ECPG_INFORMIX_DIVIDE_ZERO : 如果发现尝试除零,函数会返回这个值。在内部它被定义为 -1202(Informix定义)。

ECPG_INFORMIX_BAD_YEAR : 如果在解析一个日期时为年找到了一个坏的值,函数会返回这个值。在内部它被定义为 -1204(Informix定义)。

ECPG_INFORMIX_BAD_MONTH : 如果在解析一个日期时为月找到了一个坏的值,函数会返回这个值。在内部它被定义为 -1205(Informix定义)。

ECPG_INFORMIX_BAD_DAY : 如果在解析一个日期时为日找到了一个坏的值,函数会返回这个值。在内部它被定义为 -1206(Informix定义)。

ECPG_INFORMIX_ENOSHORTDATE : 如果一个解析例程需要一个短日期表示但是却没有得到正确长度的日期自如穿,函数会返回这个值。在内部它被定义为 -1209(Informix定义)。

ECPG_INFORMIX_DATE_CONVERT : 如果在日期格式化时产生了一个错误,函数会返回这个值。在内部它被定义为 -1210(Informix定义)。

ECPG_INFORMIX_OUT_OF_MEMORY : 如果在操作时内存被耗尽,函数会返回这个值。在内部它被定义为 -1211(Informix定义)。

ECPG_INFORMIX_ENOTDMY : 如果一个解析例程被假定为得到一个格式掩码(如mmddyy)但是列出的域并不是全部正确,函数会返回这个值。在内部它被定义为 -1212(Informix定义)。

ECPG_INFORMIX_BAD_NUMERIC : 如果一个解析例程因为一个numeric值的文本表达包含错误而不能解析它或者一个例程因为至少一个numeric变量非法而无法完成一次涉及numeric变量的计算,函数会返回这个值。在内部它被定义为 -1213(Informix定义)。

ECPG_INFORMIX_BAD_EXPONENT : 如果一个解析例程不能解析一个指数,函数会返回这个值。在内部它被定义为 -1216(Informix定义)。

ECPG_INFORMIX_BAD_DATE : 如果一个解析例程不能解析一个日期,函数会返回这个值。在内部它被定义为 -1218(Informix定义)。

ECPG_INFORMIX_EXTRA_CHARS : 如果一个解析例程被传递了它不能解析的额外字符,函数会返回这个值。在内部它被定义为 -1264(Informix定义)。