2010-09-20 22:08:53 +02:00
|
|
|
/* src/interfaces/ecpg/pgtypeslib/common.c */
|
2006-07-30 12:24:10 +02:00
|
|
|
|
2003-07-02 09:57:36 +02:00
|
|
|
#include "postgres_fe.h"
|
2003-03-20 16:56:50 +01:00
|
|
|
|
2018-06-18 08:33:53 +02:00
|
|
|
#include "pgtypes.h"
|
2019-10-23 06:08:53 +02:00
|
|
|
#include "pgtypeslib_extern.h"
|
2003-04-01 16:37:25 +02:00
|
|
|
|
2005-06-30 09:27:31 +02:00
|
|
|
/* Return value is zero-filled. */
|
2003-03-20 16:56:50 +01:00
|
|
|
char *
|
|
|
|
pgtypes_alloc(long size)
|
|
|
|
{
|
2003-08-04 02:43:34 +02:00
|
|
|
char *new = (char *) calloc(1L, size);
|
2003-03-20 16:56:50 +01:00
|
|
|
|
|
|
|
if (!new)
|
|
|
|
errno = ENOMEM;
|
2017-08-17 18:39:20 +02:00
|
|
|
return new;
|
2003-03-20 16:56:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
char *
|
2011-12-18 19:04:19 +01:00
|
|
|
pgtypes_strdup(const char *str)
|
2003-03-20 16:56:50 +01:00
|
|
|
{
|
2003-08-04 02:43:34 +02:00
|
|
|
char *new = (char *) strdup(str);
|
2003-03-20 16:56:50 +01:00
|
|
|
|
|
|
|
if (!new)
|
|
|
|
errno = ENOMEM;
|
2017-08-17 18:39:20 +02:00
|
|
|
return new;
|
2003-03-20 16:56:50 +01:00
|
|
|
}
|
|
|
|
|
2003-04-01 16:37:25 +02:00
|
|
|
int
|
2003-08-04 02:43:34 +02:00
|
|
|
pgtypes_fmt_replace(union un_fmt_comb replace_val, int replace_type, char **output, int *pstr_len)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* general purpose variable, set to 0 in order to fix compiler warning
|
|
|
|
*/
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
switch (replace_type)
|
|
|
|
{
|
2003-08-01 10:21:04 +02:00
|
|
|
case PGTYPES_TYPE_NOTHING:
|
2003-04-01 16:37:25 +02:00
|
|
|
break;
|
2003-08-01 10:21:04 +02:00
|
|
|
case PGTYPES_TYPE_STRING_CONSTANT:
|
|
|
|
case PGTYPES_TYPE_STRING_MALLOCED:
|
|
|
|
i = strlen(replace_val.str_val);
|
2003-08-04 02:43:34 +02:00
|
|
|
if (i + 1 <= *pstr_len)
|
|
|
|
{
|
2018-06-16 20:58:11 +02:00
|
|
|
/* include trailing terminator in what we copy */
|
|
|
|
memcpy(*output, replace_val.str_val, i + 1);
|
2003-04-01 16:37:25 +02:00
|
|
|
*pstr_len -= i;
|
|
|
|
*output += i;
|
2003-08-04 02:43:34 +02:00
|
|
|
if (replace_type == PGTYPES_TYPE_STRING_MALLOCED)
|
2003-08-01 10:21:04 +02:00
|
|
|
free(replace_val.str_val);
|
2003-04-01 16:37:25 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2003-08-04 02:43:34 +02:00
|
|
|
else
|
|
|
|
return -1;
|
2003-04-01 16:37:25 +02:00
|
|
|
break;
|
2003-08-01 10:21:04 +02:00
|
|
|
case PGTYPES_TYPE_CHAR:
|
2003-08-04 02:43:34 +02:00
|
|
|
if (*pstr_len >= 2)
|
|
|
|
{
|
2003-08-01 10:21:04 +02:00
|
|
|
(*output)[0] = replace_val.char_val;
|
2003-04-01 16:37:25 +02:00
|
|
|
(*output)[1] = '\0';
|
|
|
|
(*pstr_len)--;
|
|
|
|
(*output)++;
|
|
|
|
return 0;
|
|
|
|
}
|
2003-08-04 02:43:34 +02:00
|
|
|
else
|
|
|
|
return -1;
|
2003-04-01 16:37:25 +02:00
|
|
|
break;
|
2003-08-01 10:21:04 +02:00
|
|
|
case PGTYPES_TYPE_DOUBLE_NF:
|
|
|
|
case PGTYPES_TYPE_INT64:
|
|
|
|
case PGTYPES_TYPE_UINT:
|
|
|
|
case PGTYPES_TYPE_UINT_2_LZ:
|
|
|
|
case PGTYPES_TYPE_UINT_2_LS:
|
|
|
|
case PGTYPES_TYPE_UINT_3_LZ:
|
|
|
|
case PGTYPES_TYPE_UINT_4_LZ:
|
2003-04-01 16:37:25 +02:00
|
|
|
{
|
2003-08-04 02:43:34 +02:00
|
|
|
char *t = pgtypes_alloc(PGTYPES_FMT_NUM_MAX_DIGITS);
|
|
|
|
|
|
|
|
if (!t)
|
2003-04-01 16:37:25 +02:00
|
|
|
return ENOMEM;
|
2003-08-04 02:43:34 +02:00
|
|
|
switch (replace_type)
|
|
|
|
{
|
2003-08-01 10:21:04 +02:00
|
|
|
case PGTYPES_TYPE_DOUBLE_NF:
|
2003-04-01 16:37:25 +02:00
|
|
|
i = snprintf(t, PGTYPES_FMT_NUM_MAX_DIGITS,
|
2003-08-04 02:43:34 +02:00
|
|
|
"%0.0g", replace_val.double_val);
|
2003-04-01 16:37:25 +02:00
|
|
|
break;
|
2003-08-01 10:21:04 +02:00
|
|
|
case PGTYPES_TYPE_INT64:
|
2003-04-01 16:37:25 +02:00
|
|
|
i = snprintf(t, PGTYPES_FMT_NUM_MAX_DIGITS,
|
2003-08-04 02:43:34 +02:00
|
|
|
INT64_FORMAT, replace_val.int64_val);
|
2003-04-01 16:37:25 +02:00
|
|
|
break;
|
2003-08-01 10:21:04 +02:00
|
|
|
case PGTYPES_TYPE_UINT:
|
2003-08-04 02:43:34 +02:00
|
|
|
i = snprintf(t, PGTYPES_FMT_NUM_MAX_DIGITS,
|
|
|
|
"%u", replace_val.uint_val);
|
2003-04-01 16:37:25 +02:00
|
|
|
break;
|
2003-08-01 10:21:04 +02:00
|
|
|
case PGTYPES_TYPE_UINT_2_LZ:
|
2003-08-04 02:43:34 +02:00
|
|
|
i = snprintf(t, PGTYPES_FMT_NUM_MAX_DIGITS,
|
|
|
|
"%02u", replace_val.uint_val);
|
2003-04-01 16:37:25 +02:00
|
|
|
break;
|
2003-08-01 10:21:04 +02:00
|
|
|
case PGTYPES_TYPE_UINT_2_LS:
|
2003-08-04 02:43:34 +02:00
|
|
|
i = snprintf(t, PGTYPES_FMT_NUM_MAX_DIGITS,
|
|
|
|
"%2u", replace_val.uint_val);
|
2003-04-01 16:37:25 +02:00
|
|
|
break;
|
2003-08-01 10:21:04 +02:00
|
|
|
case PGTYPES_TYPE_UINT_3_LZ:
|
2003-08-04 02:43:34 +02:00
|
|
|
i = snprintf(t, PGTYPES_FMT_NUM_MAX_DIGITS,
|
|
|
|
"%03u", replace_val.uint_val);
|
2003-04-01 16:37:25 +02:00
|
|
|
break;
|
2003-08-01 10:21:04 +02:00
|
|
|
case PGTYPES_TYPE_UINT_4_LZ:
|
2003-08-04 02:43:34 +02:00
|
|
|
i = snprintf(t, PGTYPES_FMT_NUM_MAX_DIGITS,
|
|
|
|
"%04u", replace_val.uint_val);
|
2003-04-01 16:37:25 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
Clean up assorted misuses of snprintf()'s result value.
Fix a small number of places that were testing the result of snprintf()
but doing so incorrectly. The right test for buffer overrun, per C99,
is "result >= bufsize" not "result > bufsize". Some places were also
checking for failure with "result == -1", but the standard only says
that a negative value is delivered on failure.
(Note that this only makes these places correct if snprintf() delivers
C99-compliant results. But at least now these places are consistent
with all the other places where we assume that.)
Also, make psql_start_test() and isolation_start_test() check for
buffer overrun while constructing their shell commands. There seems
like a higher risk of overrun, with more severe consequences, here
than there is for the individual file paths that are made elsewhere
in the same functions, so this seemed like a worthwhile change.
Also fix guc.c's do_serialize() to initialize errno = 0 before
calling vsnprintf. In principle, this should be unnecessary because
vsnprintf should have set errno if it returns a failure indication ...
but the other two places this coding pattern is cribbed from don't
assume that, so let's be consistent.
These errors are all very old, so back-patch as appropriate. I think
that only the shell command overrun cases are even theoretically
reachable in practice, but there's not much point in erroneous error
checks.
Discussion: https://postgr.es/m/17245.1534289329@sss.pgh.pa.us
2018-08-15 22:29:31 +02:00
|
|
|
if (i < 0 || i >= PGTYPES_FMT_NUM_MAX_DIGITS)
|
2003-08-04 02:43:34 +02:00
|
|
|
{
|
2003-04-01 16:37:25 +02:00
|
|
|
free(t);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
i = strlen(t);
|
|
|
|
*pstr_len -= i;
|
2003-08-04 02:43:34 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* if *pstr_len == 0, we don't have enough space for the
|
|
|
|
* terminator and the conversion fails
|
|
|
|
*/
|
|
|
|
if (*pstr_len <= 0)
|
|
|
|
{
|
2003-04-01 16:37:25 +02:00
|
|
|
free(t);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
strcpy(*output, t);
|
|
|
|
*output += i;
|
|
|
|
free(t);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2018-06-18 08:33:53 +02:00
|
|
|
|
|
|
|
/* Functions declared in pgtypes.h. */
|
|
|
|
|
|
|
|
/* Just frees memory (mostly needed for Windows) */
|
|
|
|
void
|
|
|
|
PGTYPESchar_free(char *ptr)
|
|
|
|
{
|
|
|
|
free(ptr);
|
|
|
|
}
|