Peter Eisentraut cb05ab81a8 NLS cleanup in ecpglib
Replace leftover instances of _() by ecpg_gettext(), the latter being the
correct way to refer to the library's message catalog, instead of the one of
the program using the library.

Drop NLS support for ecpg_log(), which is a debugging instrument similar to
elog() in the backend.

We cannot support NLS in the ecpg compatlib, because that requires
ecpg_gettext, which is in ecpglib, which is not a dependency of compatlib.  It
doesn't seem worthwhile to worry about this, since the only translatable
string is "out of memory", and gettext probably won't be able to do much
without memory either.

Adjust messages to project style.
2009-01-15 11:52:55 +00:00

1048 lines
18 KiB
C

/* $PostgreSQL: pgsql/src/interfaces/ecpg/compatlib/informix.c,v 1.57 2009/01/15 11:52:54 petere Exp $ */
#define POSTGRES_ECPG_INTERNAL
#include "postgres_fe.h"
#include <math.h>
#include <ctype.h>
#include <limits.h>
#include <ecpgtype.h>
#include <ecpg_informix.h>
#include <pgtypes_error.h>
#include <pgtypes_date.h>
#include <pgtypes_numeric.h>
#include <sqltypes.h>
#include <sqlca.h>
#include <ecpgerrno.h>
static int
deccall2(decimal *arg1, decimal *arg2, int (*ptr) (numeric *, numeric *))
{
numeric *a1,
*a2;
int i;
if ((a1 = PGTYPESnumeric_new()) == NULL)
return ECPG_INFORMIX_OUT_OF_MEMORY;
if ((a2 = PGTYPESnumeric_new()) == NULL)
{
PGTYPESnumeric_free(a1);
return ECPG_INFORMIX_OUT_OF_MEMORY;
}
if (PGTYPESnumeric_from_decimal(arg1, a1) != 0)
{
PGTYPESnumeric_free(a1);
PGTYPESnumeric_free(a2);
return ECPG_INFORMIX_OUT_OF_MEMORY;
}
if (PGTYPESnumeric_from_decimal(arg2, a2) != 0)
{
PGTYPESnumeric_free(a1);
PGTYPESnumeric_free(a2);
return ECPG_INFORMIX_OUT_OF_MEMORY;
}
i = (*ptr) (a1, a2);
PGTYPESnumeric_free(a1);
PGTYPESnumeric_free(a2);
return (i);
}
static int
deccall3(decimal *arg1, decimal *arg2, decimal *result, int (*ptr) (numeric *, numeric *, numeric *))
{
numeric *a1,
*a2,
*nres;
int i;
/*
* we must NOT set the result to NULL here because it may be the same
* variable as one of the arguments
*/
if (risnull(CDECIMALTYPE, (char *) arg1) || risnull(CDECIMALTYPE, (char *) arg2))
return 0;
if ((a1 = PGTYPESnumeric_new()) == NULL)
return ECPG_INFORMIX_OUT_OF_MEMORY;
if ((a2 = PGTYPESnumeric_new()) == NULL)
{
PGTYPESnumeric_free(a1);
return ECPG_INFORMIX_OUT_OF_MEMORY;
}
if ((nres = PGTYPESnumeric_new()) == NULL)
{
PGTYPESnumeric_free(a1);
PGTYPESnumeric_free(a2);
return ECPG_INFORMIX_OUT_OF_MEMORY;
}
if (PGTYPESnumeric_from_decimal(arg1, a1) != 0)
{
PGTYPESnumeric_free(a1);
PGTYPESnumeric_free(a2);
PGTYPESnumeric_free(nres);
return ECPG_INFORMIX_OUT_OF_MEMORY;
}
if (PGTYPESnumeric_from_decimal(arg2, a2) != 0)
{
PGTYPESnumeric_free(a1);
PGTYPESnumeric_free(a2);
PGTYPESnumeric_free(nres);
return ECPG_INFORMIX_OUT_OF_MEMORY;
}
i = (*ptr) (a1, a2, nres);
if (i == 0) /* No error */
{
/* set the result to null in case it errors out later */
rsetnull(CDECIMALTYPE, (char *) result);
PGTYPESnumeric_to_decimal(nres, result);
}
PGTYPESnumeric_free(nres);
PGTYPESnumeric_free(a1);
PGTYPESnumeric_free(a2);
return (i);
}
/* we start with the numeric functions */
int
decadd(decimal *arg1, decimal *arg2, decimal *sum)
{
errno = 0;
deccall3(arg1, arg2, sum, PGTYPESnumeric_add);
if (errno == PGTYPES_NUM_OVERFLOW)
return ECPG_INFORMIX_NUM_OVERFLOW;
else if (errno == PGTYPES_NUM_UNDERFLOW)
return ECPG_INFORMIX_NUM_UNDERFLOW;
else if (errno != 0)
return -1;
else
return 0;
}
int
deccmp(decimal *arg1, decimal *arg2)
{
return (deccall2(arg1, arg2, PGTYPESnumeric_cmp));
}
void
deccopy(decimal *src, decimal *target)
{
memcpy(target, src, sizeof(decimal));
}
static char *
ecpg_strndup(const char *str, size_t len)
{
int real_len = strlen(str);
int use_len = (real_len > len) ? len : real_len;
char *new = malloc(use_len + 1);
if (new)
{
memcpy(new, str, use_len);
new[use_len] = '\0';
}
else
errno = ENOMEM;
return new;
}
int
deccvasc(char *cp, int len, decimal *np)
{
char *str;
int ret = 0;
numeric *result;
rsetnull(CDECIMALTYPE, (char *) np);
if (risnull(CSTRINGTYPE, cp))
return 0;
str = ecpg_strndup(cp, len);/* decimal_in always converts the complete
* string */
if (!str)
ret = ECPG_INFORMIX_NUM_UNDERFLOW;
else
{
errno = 0;
result = PGTYPESnumeric_from_asc(str, NULL);
if (!result)
{
switch (errno)
{
case PGTYPES_NUM_OVERFLOW:
ret = ECPG_INFORMIX_NUM_OVERFLOW;
break;
case PGTYPES_NUM_BAD_NUMERIC:
ret = ECPG_INFORMIX_BAD_NUMERIC;
break;
default:
ret = ECPG_INFORMIX_BAD_EXPONENT;
break;
}
}
else
{
int i = PGTYPESnumeric_to_decimal(result, np);
free(result);
if (i != 0)
ret = ECPG_INFORMIX_NUM_OVERFLOW;
}
}
free(str);
return ret;
}
int
deccvdbl(double dbl, decimal *np)
{
numeric *nres;
int result = 1;
rsetnull(CDECIMALTYPE, (char *) np);
if (risnull(CDOUBLETYPE, (char *) &dbl))
return 0;
nres = PGTYPESnumeric_new();
if (nres == NULL)
return ECPG_INFORMIX_OUT_OF_MEMORY;
result = PGTYPESnumeric_from_double(dbl, nres);
if (result == 0)
result = PGTYPESnumeric_to_decimal(nres, np);
PGTYPESnumeric_free(nres);
return (result);
}
int
deccvint(int in, decimal *np)
{
numeric *nres;
int result = 1;
rsetnull(CDECIMALTYPE, (char *) np);
if (risnull(CINTTYPE, (char *) &in))
return 0;
nres = PGTYPESnumeric_new();
if (nres == NULL)
return ECPG_INFORMIX_OUT_OF_MEMORY;
result = PGTYPESnumeric_from_int(in, nres);
if (result == 0)
result = PGTYPESnumeric_to_decimal(nres, np);
PGTYPESnumeric_free(nres);
return (result);
}
int
deccvlong(long lng, decimal *np)
{
numeric *nres;
int result = 1;
rsetnull(CDECIMALTYPE, (char *) np);
if (risnull(CLONGTYPE, (char *) &lng))
return 0;
nres = PGTYPESnumeric_new();
if (nres == NULL)
return ECPG_INFORMIX_OUT_OF_MEMORY;
result = PGTYPESnumeric_from_long(lng, nres);
if (result == 0)
result = PGTYPESnumeric_to_decimal(nres, np);
PGTYPESnumeric_free(nres);
return (result);
}
int
decdiv(decimal *n1, decimal *n2, decimal *result)
{
int i;
errno = 0;
i = deccall3(n1, n2, result, PGTYPESnumeric_div);
if (i != 0)
switch (errno)
{
case PGTYPES_NUM_DIVIDE_ZERO:
return ECPG_INFORMIX_DIVIDE_ZERO;
break;
case PGTYPES_NUM_OVERFLOW:
return ECPG_INFORMIX_NUM_OVERFLOW;
break;
default:
return ECPG_INFORMIX_NUM_UNDERFLOW;
break;
}
return 0;
}
int
decmul(decimal *n1, decimal *n2, decimal *result)
{
int i;
errno = 0;
i = deccall3(n1, n2, result, PGTYPESnumeric_mul);
if (i != 0)
switch (errno)
{
case PGTYPES_NUM_OVERFLOW:
return ECPG_INFORMIX_NUM_OVERFLOW;
break;
default:
return ECPG_INFORMIX_NUM_UNDERFLOW;
break;
}
return 0;
}
int
decsub(decimal *n1, decimal *n2, decimal *result)
{
int i;
errno = 0;
i = deccall3(n1, n2, result, PGTYPESnumeric_sub);
if (i != 0)
switch (errno)
{
case PGTYPES_NUM_OVERFLOW:
return ECPG_INFORMIX_NUM_OVERFLOW;
break;
default:
return ECPG_INFORMIX_NUM_UNDERFLOW;
break;
}
return 0;
}
int
dectoasc(decimal *np, char *cp, int len, int right)
{
char *str;
numeric *nres;
rsetnull(CSTRINGTYPE, (char *) cp);
if (risnull(CDECIMALTYPE, (char *) np))
return 0;
nres = PGTYPESnumeric_new();
if (nres == NULL)
return ECPG_INFORMIX_OUT_OF_MEMORY;
if (PGTYPESnumeric_from_decimal(np, nres) != 0)
{
PGTYPESnumeric_free(nres);
return ECPG_INFORMIX_OUT_OF_MEMORY;
}
if (right >= 0)
str = PGTYPESnumeric_to_asc(nres, right);
else
str = PGTYPESnumeric_to_asc(nres, nres->dscale);
PGTYPESnumeric_free(nres);
if (!str)
return -1;
/*
* TODO: have to take care of len here and create exponential notation if
* necessary
*/
if ((int) (strlen(str) + 1) > len)
{
if (len > 1)
{
cp[0] = '*';
cp[1] = '\0';
}
free(str);
return -1;
}
else
{
strcpy(cp, str);
free(str);
return 0;
}
}
int
dectodbl(decimal *np, double *dblp)
{
int i;
numeric *nres = PGTYPESnumeric_new();
if (nres == NULL)
return ECPG_INFORMIX_OUT_OF_MEMORY;
if (PGTYPESnumeric_from_decimal(np, nres) != 0)
{
PGTYPESnumeric_free(nres);
return ECPG_INFORMIX_OUT_OF_MEMORY;
}
i = PGTYPESnumeric_to_double(nres, dblp);
PGTYPESnumeric_free(nres);
return i;
}
int
dectoint(decimal *np, int *ip)
{
int ret;
numeric *nres = PGTYPESnumeric_new();
if (nres == NULL)
return ECPG_INFORMIX_OUT_OF_MEMORY;
if (PGTYPESnumeric_from_decimal(np, nres) != 0)
{
PGTYPESnumeric_free(nres);
return ECPG_INFORMIX_OUT_OF_MEMORY;
}
ret = PGTYPESnumeric_to_int(nres, ip);
PGTYPESnumeric_free(nres);
if (ret == PGTYPES_NUM_OVERFLOW)
ret = ECPG_INFORMIX_NUM_OVERFLOW;
return ret;
}
int
dectolong(decimal *np, long *lngp)
{
int ret;
numeric *nres = PGTYPESnumeric_new();
if (nres == NULL)
return ECPG_INFORMIX_OUT_OF_MEMORY;
if (PGTYPESnumeric_from_decimal(np, nres) != 0)
{
PGTYPESnumeric_free(nres);
return ECPG_INFORMIX_OUT_OF_MEMORY;
}
ret = PGTYPESnumeric_to_long(nres, lngp);
PGTYPESnumeric_free(nres);
if (ret == PGTYPES_NUM_OVERFLOW)
ret = ECPG_INFORMIX_NUM_OVERFLOW;
return ret;
}
/* Now the date functions */
int
rdatestr(date d, char *str)
{
char *tmp = PGTYPESdate_to_asc(d);
if (!tmp)
return ECPG_INFORMIX_DATE_CONVERT;
/* move to user allocated buffer */
strcpy(str, tmp);
free(tmp);
return 0;
}
/*
*
* the input for this function is mmddyyyy and any non-numeric
* character can be used as a separator
*
*/
int
rstrdate(char *str, date * d)
{
return rdefmtdate(d, "mm/dd/yyyy", str);
}
void
rtoday(date * d)
{
PGTYPESdate_today(d);
return;
}
int
rjulmdy(date d, short mdy[3])
{
int mdy_int[3];
PGTYPESdate_julmdy(d, mdy_int);
mdy[0] = (short) mdy_int[0];
mdy[1] = (short) mdy_int[1];
mdy[2] = (short) mdy_int[2];
return 0;
}
int
rdefmtdate(date * d, char *fmt, char *str)
{
/* TODO: take care of DBCENTURY environment variable */
/* PGSQL functions allow all centuries */
errno = 0;
if (PGTYPESdate_defmt_asc(d, fmt, str) == 0)
return 0;
switch (errno)
{
case PGTYPES_DATE_ERR_ENOSHORTDATE:
return ECPG_INFORMIX_ENOSHORTDATE;
case PGTYPES_DATE_ERR_EARGS:
case PGTYPES_DATE_ERR_ENOTDMY:
return ECPG_INFORMIX_ENOTDMY;
case PGTYPES_DATE_BAD_DAY:
return ECPG_INFORMIX_BAD_DAY;
case PGTYPES_DATE_BAD_MONTH:
return ECPG_INFORMIX_BAD_MONTH;
default:
return ECPG_INFORMIX_BAD_YEAR;
}
}
int
rfmtdate(date d, char *fmt, char *str)
{
errno = 0;
if (PGTYPESdate_fmt_asc(d, fmt, str) == 0)
return 0;
if (errno == ENOMEM)
return ECPG_INFORMIX_OUT_OF_MEMORY;
return ECPG_INFORMIX_DATE_CONVERT;
}
int
rmdyjul(short mdy[3], date * d)
{
int mdy_int[3];
mdy_int[0] = mdy[0];
mdy_int[1] = mdy[1];
mdy_int[2] = mdy[2];
PGTYPESdate_mdyjul(mdy_int, d);
return 0;
}
int
rdayofweek(date d)
{
return (PGTYPESdate_dayofweek(d));
}
/* And the datetime stuff */
void
dtcurrent(timestamp * ts)
{
PGTYPEStimestamp_current(ts);
}
int
dtcvasc(char *str, timestamp * ts)
{
timestamp ts_tmp;
int i;
char **endptr = &str;
errno = 0;
ts_tmp = PGTYPEStimestamp_from_asc(str, endptr);
i = errno;
if (i)
/* TODO: rewrite to Informix error codes */
return i;
if (**endptr)
{
/* extra characters exist at the end */
return ECPG_INFORMIX_EXTRA_CHARS;
}
/* TODO: other Informix error codes missing */
/* everything went fine */
*ts = ts_tmp;
return 0;
}
int
dtcvfmtasc(char *inbuf, char *fmtstr, timestamp * dtvalue)
{
return PGTYPEStimestamp_defmt_asc(inbuf, fmtstr, dtvalue);
}
int
dtsub(timestamp * ts1, timestamp * ts2, interval * iv)
{
return PGTYPEStimestamp_sub(ts1, ts2, iv);
}
int
dttoasc(timestamp * ts, char *output)
{
char *asctime = PGTYPEStimestamp_to_asc(*ts);
strcpy(output, asctime);
free(asctime);
return 0;
}
int
dttofmtasc(timestamp * ts, char *output, int str_len, char *fmtstr)
{
return PGTYPEStimestamp_fmt_asc(ts, output, str_len, fmtstr);
}
int
intoasc(interval * i, char *str)
{
errno = 0;
str = PGTYPESinterval_to_asc(i);
if (!str)
return -errno;
return 0;
}
/*
* rfmt.c - description
* by Carsten Wolff <carsten.wolff@credativ.de>, Wed Apr 2 2003
*/
static struct
{
long val;
int maxdigits;
int digits;
int remaining;
char sign;
char *val_string;
} value;
/**
* initialize the struct, which holds the different forms
* of the long value
*/
static int
initValue(long lng_val)
{
int i,
j;
long l,
dig;
/* set some obvious things */
value.val = lng_val >= 0 ? lng_val : lng_val * (-1);
value.sign = lng_val >= 0 ? '+' : '-';
value.maxdigits = log10(2) * (8 * sizeof(long) - 1);
/* determine the number of digits */
i = 0;
l = 1;
do
{
i++;
l *= 10;
}
while ((l - 1) < value.val && l <= LONG_MAX / 10);
if (l <= LONG_MAX / 10)
{
value.digits = i;
l /= 10;
}
else
value.digits = i + 1;
value.remaining = value.digits;
/* convert the long to string */
if ((value.val_string = (char *) malloc(value.digits + 1)) == NULL)
return -1;
dig = value.val;
for (i = value.digits, j = 0; i > 0; i--, j++)
{
value.val_string[j] = dig / l + '0';
dig = dig % l;
l /= 10;
}
value.val_string[value.digits] = '\0';
return 0;
}
/* return the position oft the right-most dot in some string */
static int
getRightMostDot(char *str)
{
size_t len = strlen(str);
int i,
j;
j = 0;
for (i = len - 1; i >= 0; i--)
{
if (str[i] == '.')
return len - j - 1;
j++;
}
return -1;
}
/* And finally some misc functions */
int
rfmtlong(long lng_val, char *fmt, char *outbuf)
{
size_t fmt_len = strlen(fmt);
size_t temp_len;
int i,
j,
k,
dotpos;
int leftalign = 0,
blank = 0,
sign = 0,
entity = 0,
entitydone = 0,
signdone = 0,
brackets_ok = 0;
char *temp;
char tmp[2] = " ";
char lastfmt = ' ',
fmtchar = ' ';
temp = (char *) malloc(fmt_len + 1);
if (!temp)
{
errno = ENOMEM;
return -1;
}
/* put all info about the long in a struct */
if (initValue(lng_val) == -1)
{
free(temp);
errno = ENOMEM;
return -1;
}
/* '<' is the only format, where we have to align left */
if (strchr(fmt, (int) '<'))
leftalign = 1;
/* '(' requires ')' */
if (strchr(fmt, (int) '(') && strchr(fmt, (int) ')'))
brackets_ok = 1;
/* get position of the right-most dot in the format-string */
/* and fill the temp-string wit '0's up to there. */
dotpos = getRightMostDot(fmt);
/* start to parse the formatstring */
temp[0] = '\0';
j = 0; /* position in temp */
k = value.digits - 1; /* position in the value_string */
for (i = fmt_len - 1, j = 0; i >= 0; i--, j++)
{
/* qualify, where we are in the value_string */
if (k < 0)
{
blank = 1;
if (k == -2)
entity = 1;
else if (k == -1)
sign = 1;
if (leftalign)
{
/* can't use strncat(,,0) here, Solaris would freek out */
if (sign)
if (signdone)
{
temp[j] = '\0';
break;
}
}
}
/* if we're right side of the right-most dot, print '0' */
if (dotpos >= 0 && dotpos <= i)
{
if (dotpos < i)
{
if (fmt[i] == ')')
tmp[0] = value.sign == '-' ? ')' : ' ';
else
tmp[0] = '0';
}
else
tmp[0] = '.';
strcat(temp, tmp);
continue;
}
/* the ',' needs special attention, if it is in the blank area */
if (blank && fmt[i] == ',')
fmtchar = lastfmt;
else
fmtchar = fmt[i];
/* waiting for the sign */
if (k < 0 && leftalign && sign && !signdone && fmtchar != '+' && fmtchar != '-')
continue;
/* analyse this format-char */
switch (fmtchar)
{
case ',':
tmp[0] = ',';
k++;
break;
case '*':
if (blank)
tmp[0] = '*';
else
tmp[0] = value.val_string[k];
break;
case '&':
if (blank)
tmp[0] = '0';
else
tmp[0] = value.val_string[k];
break;
case '#':
if (blank)
tmp[0] = ' ';
else
tmp[0] = value.val_string[k];
break;
case '-':
if (sign && value.sign == '-' && !signdone)
{
tmp[0] = '-';
signdone = 1;
}
else if (blank)
tmp[0] = ' ';
else
tmp[0] = value.val_string[k];
break;
case '+':
if (sign && !signdone)
{
tmp[0] = value.sign;
signdone = 1;
}
else if (blank)
tmp[0] = ' ';
else
tmp[0] = value.val_string[k];
break;
case '(':
if (sign && brackets_ok && value.sign == '-')
tmp[0] = '(';
else if (blank)
tmp[0] = ' ';
else
tmp[0] = value.val_string[k];
break;
case ')':
if (brackets_ok && value.sign == '-')
tmp[0] = ')';
else
tmp[0] = ' ';
break;
case '$':
if (blank && !entitydone)
{
tmp[0] = '$';
entitydone = 1;
}
else if (blank)
tmp[0] = ' ';
else
tmp[0] = value.val_string[k];
break;
case '<':
tmp[0] = value.val_string[k];
break;
default:
tmp[0] = fmt[i];
}
strcat(temp, tmp);
lastfmt = fmt[i];
k--;
}
/* safety-net */
temp[fmt_len] = '\0';
/* reverse the temp-string and put it into the outbuf */
temp_len = strlen(temp);
outbuf[0] = '\0';
for (i = temp_len - 1; i >= 0; i--)
{
tmp[0] = temp[i];
strcat(outbuf, tmp);
}
outbuf[temp_len] = '\0';
/* cleaning up */
free(temp);
free(value.val_string);
return 0;
}
void
rupshift(char *str)
{
for (; *str != '\0'; str++)
if (islower((unsigned char) *str))
*str = toupper((unsigned char) *str);
return;
}
int
byleng(char *str, int len)
{
for (len--; str[len] && str[len] == ' '; len--);
return (len + 1);
}
void
ldchar(char *src, int len, char *dest)
{
int dlen = byleng(src, len);
memmove(dest, src, dlen);
dest[dlen] = '\0';
}
int
rgetmsg(int msgnum, char *s, int maxsize)
{
return 0;
}
int
rtypalign(int offset, int type)
{
return 0;
}
int
rtypmsize(int type, int len)
{
return 0;
}
int
rtypwidth(int sqltype, int sqllen)
{
return 0;
}
static struct var_list
{
int number;
void *pointer;
struct var_list *next;
} *ivlist = NULL;
void
ECPG_informix_set_var(int number, void *pointer, int lineno)
{
struct var_list *ptr;
for (ptr = ivlist; ptr != NULL; ptr = ptr->next)
{
if (ptr->number == number)
{
/* already known => just change pointer value */
ptr->pointer = pointer;
return;
}
}
/* a new one has to be added */
ptr = (struct var_list *) calloc(1L, sizeof(struct var_list));
if (!ptr)
{
struct sqlca_t *sqlca = ECPGget_sqlca();
sqlca->sqlcode = ECPG_OUT_OF_MEMORY;
strncpy(sqlca->sqlstate, "YE001", sizeof("YE001"));
snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc), "out of memory on line %d", lineno);
sqlca->sqlerrm.sqlerrml = strlen(sqlca->sqlerrm.sqlerrmc);
/* free all memory we have allocated for the user */
ECPGfree_auto_mem();
}
else
{
ptr->number = number;
ptr->pointer = pointer;
ptr->next = ivlist;
ivlist = ptr;
}
}
void *
ECPG_informix_get_var(int number)
{
struct var_list *ptr;
for (ptr = ivlist; ptr != NULL && ptr->number != number; ptr = ptr->next);
return (ptr) ? ptr->pointer : NULL;
}
int
rsetnull(int t, char *ptr)
{
ECPGset_noind_null(t, ptr);
return 0;
}
int
risnull(int t, char *ptr)
{
return (ECPGis_noind_null(t, ptr));
}