Remove arbitrary FUNC_MAX_ARGS limit in int2vectorin and oidvectorin.
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 15 Jan 2023 22:32:09 +0000 (17:32 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 15 Jan 2023 22:32:09 +0000 (17:32 -0500)
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

src/backend/utils/adt/int.c
src/backend/utils/adt/oid.c

index e47c15a54f605e2a64d186bf6f4f2b628ec577db..44d1c7ad0c4d770acc33f35bb57080bac7670e5c 100644 (file)
@@ -143,11 +143,13 @@ int2vectorin(PG_FUNCTION_ARGS)
    char       *intString = PG_GETARG_CSTRING(0);
    Node       *escontext = fcinfo->context;
    int2vector *result;
+   int         nalloc;
    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;
        char       *endp;
@@ -157,6 +159,12 @@ int2vectorin(PG_FUNCTION_ARGS)
        if (*intString == '\0')
            break;
 
+       if (n >= nalloc)
+       {
+           nalloc *= 2;
+           result = (int2vector *) repalloc(result, Int2VectorSize(nalloc));
+       }
+
        errno = 0;
        l = strtol(intString, &endp, 10);
 
@@ -176,17 +184,11 @@ int2vectorin(PG_FUNCTION_ARGS)
            ereturn(escontext, (Datum) 0,
                    (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
                     errmsg("invalid input syntax for type %s: \"%s\"",
-                           "integer", intString)));
+                           "smallint", intString)));
 
        result->values[n] = l;
        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));
    result->ndim = 1;
@@ -261,12 +263,6 @@ int2vectorrecv(PG_FUNCTION_ARGS)
                (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
                 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);
 }
 
index 697588313da6600cce9483277e1bb9ddd300a76d..3f7af5b3a066148a7b8bfbae3eaa3a338e527a6e 100644 (file)
@@ -115,27 +115,30 @@ oidvectorin(PG_FUNCTION_ARGS)
    char       *oidString = PG_GETARG_CSTRING(0);
    Node       *escontext = fcinfo->context;
    oidvector  *result;
+   int         nalloc;
    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))
            oidString++;
        if (*oidString == '\0')
            break;
+
+       if (n >= nalloc)
+       {
+           nalloc *= 2;
+           result = (oidvector *) repalloc(result, OidVectorSize(nalloc));
+       }
+
        result->values[n] = uint32in_subr(oidString, &oidString,
                                          "oid", escontext);
        if (SOFT_ERROR_OCCURRED(escontext))
            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));
    result->ndim = 1;
@@ -212,12 +215,6 @@ oidvectorrecv(PG_FUNCTION_ARGS)
                (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
                 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);
 }