Remove arbitrary FUNC_MAX_ARGS limit in int2vectorin and oidvectorin.

int2vectorin limited the number of array elements it'd take to
FUNC_MAX_ARGS, which is probably fine for the traditional use-cases.
But now that pg_publication_rel.prattrs is an int2vector, it's not
fine at all: it's easy to construct cases where that can have up to
about MaxTupleAttributeNumber entries.  Trying to replicate such
tables leads to logical-replication failures.

As long as we have to touch this code anyway, let's just remove
the a-priori limit altogether, and let it accept any size that'll
be allowed by repalloc.  (Note that since int2vector isn't toastable,
we cannot store arrays longer than about BLCKSZ/2; but there is no
good excuse for letting int2vectorin depend on that.  Perhaps we
will lift the no-toast restriction someday.)

While at it, also improve the equivalent logic in oidvectorin.
I don't know of any practical use-case for long oidvectors right
now, but doing it right actually makes the code shorter.

Per report from Erik Rijkers.  Back-patch to v15 where
pg_publication_rel.prattrs was added.

Discussion: https://postgr.es/m/668ba539-33c5-8190-ca11-def2913cb94b@xs4all.nl
This commit is contained in:
Tom Lane 2023-01-15 17:32:09 -05:00
parent 3f244d020f
commit 647fa50054
2 changed files with 22 additions and 29 deletions

View File

@ -143,11 +143,13 @@ int2vectorin(PG_FUNCTION_ARGS)
char *intString = PG_GETARG_CSTRING(0); char *intString = PG_GETARG_CSTRING(0);
Node *escontext = fcinfo->context; Node *escontext = fcinfo->context;
int2vector *result; int2vector *result;
int nalloc;
int n; int n;
result = (int2vector *) palloc0(Int2VectorSize(FUNC_MAX_ARGS)); nalloc = 32; /* arbitrary initial size guess */
result = (int2vector *) palloc0(Int2VectorSize(nalloc));
for (n = 0; n < FUNC_MAX_ARGS; n++) for (n = 0;; n++)
{ {
long l; long l;
char *endp; char *endp;
@ -157,6 +159,12 @@ int2vectorin(PG_FUNCTION_ARGS)
if (*intString == '\0') if (*intString == '\0')
break; break;
if (n >= nalloc)
{
nalloc *= 2;
result = (int2vector *) repalloc(result, Int2VectorSize(nalloc));
}
errno = 0; errno = 0;
l = strtol(intString, &endp, 10); l = strtol(intString, &endp, 10);
@ -176,17 +184,11 @@ int2vectorin(PG_FUNCTION_ARGS)
ereturn(escontext, (Datum) 0, ereturn(escontext, (Datum) 0,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type %s: \"%s\"", errmsg("invalid input syntax for type %s: \"%s\"",
"integer", intString))); "smallint", intString)));
result->values[n] = l; result->values[n] = l;
intString = endp; intString = endp;
} }
while (*intString && isspace((unsigned char) *intString))
intString++;
if (*intString)
ereturn(escontext, (Datum) 0,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("int2vector has too many elements")));
SET_VARSIZE(result, Int2VectorSize(n)); SET_VARSIZE(result, Int2VectorSize(n));
result->ndim = 1; result->ndim = 1;
@ -261,12 +263,6 @@ int2vectorrecv(PG_FUNCTION_ARGS)
(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
errmsg("invalid int2vector data"))); errmsg("invalid int2vector data")));
/* check length for consistency with int2vectorin() */
if (ARR_DIMS(result)[0] > FUNC_MAX_ARGS)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("oidvector has too many elements")));
PG_RETURN_POINTER(result); PG_RETURN_POINTER(result);
} }

View File

@ -115,27 +115,30 @@ oidvectorin(PG_FUNCTION_ARGS)
char *oidString = PG_GETARG_CSTRING(0); char *oidString = PG_GETARG_CSTRING(0);
Node *escontext = fcinfo->context; Node *escontext = fcinfo->context;
oidvector *result; oidvector *result;
int nalloc;
int n; int n;
result = (oidvector *) palloc0(OidVectorSize(FUNC_MAX_ARGS)); nalloc = 32; /* arbitrary initial size guess */
result = (oidvector *) palloc0(OidVectorSize(nalloc));
for (n = 0; n < FUNC_MAX_ARGS; n++) for (n = 0;; n++)
{ {
while (*oidString && isspace((unsigned char) *oidString)) while (*oidString && isspace((unsigned char) *oidString))
oidString++; oidString++;
if (*oidString == '\0') if (*oidString == '\0')
break; break;
if (n >= nalloc)
{
nalloc *= 2;
result = (oidvector *) repalloc(result, OidVectorSize(nalloc));
}
result->values[n] = uint32in_subr(oidString, &oidString, result->values[n] = uint32in_subr(oidString, &oidString,
"oid", escontext); "oid", escontext);
if (SOFT_ERROR_OCCURRED(escontext)) if (SOFT_ERROR_OCCURRED(escontext))
PG_RETURN_NULL(); PG_RETURN_NULL();
} }
while (*oidString && isspace((unsigned char) *oidString))
oidString++;
if (*oidString)
ereturn(escontext, (Datum) 0,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("oidvector has too many elements")));
SET_VARSIZE(result, OidVectorSize(n)); SET_VARSIZE(result, OidVectorSize(n));
result->ndim = 1; result->ndim = 1;
@ -212,12 +215,6 @@ oidvectorrecv(PG_FUNCTION_ARGS)
(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
errmsg("invalid oidvector data"))); errmsg("invalid oidvector data")));
/* check length for consistency with oidvectorin() */
if (ARR_DIMS(result)[0] > FUNC_MAX_ARGS)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("oidvector has too many elements")));
PG_RETURN_POINTER(result); PG_RETURN_POINTER(result);
} }