1
0
mirror of https://github.com/postgres/postgres.git synced 2025-05-12 16:21:30 +03:00
Tom Lane 25f9a72662 Make ecpg's rjulmdy() and rmdyjul() agree with their declarations.
We had "short *mdy" in the extern declarations, but "short mdy[3]"
in the actual function definitions.  Per C99 these are equivalent,
but recent versions of gcc have started to issue warnings about
the inconsistency.  Clean it up before the warnings get any more
widespread.

Back-patch, in case anyone wants to build older PG versions with
bleeding-edge compilers.

Discussion: https://postgr.es/m/2401575.1611764534@sss.pgh.pa.us
2021-01-28 11:17:33 -05:00

1054 lines
18 KiB
C

/* src/interfaces/ecpg/compatlib/informix.c */
#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>
/* this is also defined in ecpglib/misc.c, by defining it twice we don't have to export the symbol */
static struct sqlca_t sqlca_init =
{
{
'S', 'Q', 'L', 'C', 'A', ' ', ' ', ' '
},
sizeof(struct sqlca_t),
0,
{
0,
{
0
}
},
{
'N', 'O', 'T', ' ', 'S', 'E', 'T', ' '
},
{
0, 0, 0, 0, 0, 0
},
{
0, 0, 0, 0, 0, 0, 0, 0
},
{
'0', '0', '0', '0', '0'
}
};
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)
{
size_t real_len = strlen(str);
int use_len = (int) ((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(const 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);
PGTYPESnumeric_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(const 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)
{
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, const char *fmt, const 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, const 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, 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)
{
char *tmp;
errno = 0;
tmp = PGTYPESinterval_to_asc(i);
if (!tmp)
return -errno;
memcpy(str, tmp, strlen(tmp));
free(tmp);
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(const 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, const char *fmt, char *outbuf)
{
size_t fmt_len = strlen(fmt);
size_t temp_len;
int i,
j, /* position in temp */
k,
dotpos;
int leftalign = 0,
blank = 0,
sign = 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';
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 == -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)
{
(void) msgnum; /* keep the compiler quiet */
(void) s; /* keep the compiler quiet */
(void) maxsize; /* keep the compiler quiet */
return 0;
}
int
rtypalign(int offset, int type)
{
(void) offset; /* keep the compiler quiet */
(void) type; /* keep the compiler quiet */
return 0;
}
int
rtypmsize(int type, int len)
{
(void) type; /* keep the compiler quiet */
(void) len; /* keep the compiler quiet */
return 0;
}
int
rtypwidth(int sqltype, int sqllen)
{
(void) sqltype; /* keep the compiler quiet */
(void) sqllen; /* keep the compiler quiet */
return 0;
}
void
ECPG_informix_set_var(int number, void *pointer, int lineno)
{
ECPGset_var(number, pointer, lineno);
}
void *
ECPG_informix_get_var(int number)
{
return ECPGget_var(number);
}
void
ECPG_informix_reset_sqlca(void)
{
struct sqlca_t *sqlca = ECPGget_sqlca();
if (sqlca == NULL)
return;
memcpy((char *) sqlca, (char *) &sqlca_init, sizeof(struct sqlca_t));
}
int
rsetnull(int t, char *ptr)
{
ECPGset_noind_null(t, ptr);
return 0;
}
int
risnull(int t, const char *ptr)
{
return ECPGis_noind_null(t, ptr);
}