diff --git a/src/bin/pg_dump/common.c b/src/bin/pg_dump/common.c index 2d2640c4e3e..52e64ace784 100644 --- a/src/bin/pg_dump/common.c +++ b/src/bin/pg_dump/common.c @@ -1130,38 +1130,138 @@ findParentsByOid(TableInfo *self, /* * parseOidArray - * parse a string of numbers delimited by spaces into a character array + * parse a string of unsigned numbers separated by spaces + * into an array of OIDs * - * Note: actually this is used for both Oids and potentially-signed - * attribute numbers. This should cause no trouble, but we could split - * the function into two functions with different argument types if it does. + * The result is a malloc'd array. + * + * If arraysize >= 0, we insist that the input contain exactly that many + * OIDs, and the allocated array is of that length too. If arraysize < 0, + * we dynamically size the array to have one more entry than the input + * provides, and fill the extra entry with zero. */ - -void -parseOidArray(const char *str, Oid *array, int arraysize) +Oid * +parseOidArray(const char *str, int arraysize) { - int j, - argNum; - char temp[100]; - char s; + Oid *array; + int allocsize, + argNum, + templen; + char temp[32]; - argNum = 0; - j = 0; - for (;;) + if (arraysize >= 0) + allocsize = arraysize; + else { - s = *str++; + /* + * Make enough room for input + one extra entry (could be more than + * enough, if there are redundant spaces in the input). + */ + allocsize = 2; + for (const char *s1 = str; *s1; s1++) + { + if (*s1 == ' ') + allocsize++; + } + } + array = pg_malloc_array(Oid, allocsize); + argNum = 0; + templen = 0; + for (const char *s1 = str;; s1++) + { + char s = *s1; + if (s == ' ' || s == '\0') { - if (j > 0) + if (templen > 0) { - if (argNum >= arraysize) + if (arraysize >= 0 && argNum >= arraysize) { pg_log_error("could not parse numeric array \"%s\": too many numbers", str); exit_nicely(1); } - temp[j] = '\0'; + temp[templen] = '\0'; array[argNum++] = atooid(temp); - j = 0; + templen = 0; + } + if (s == '\0') + break; + } + else + { + if (!isdigit((unsigned char) s) || + templen >= sizeof(temp) - 1) + { + pg_log_error("could not parse numeric array \"%s\": invalid character in number", str); + exit_nicely(1); + } + temp[templen++] = s; + } + } + + if (arraysize >= 0 && argNum != arraysize) + { + pg_log_error("could not parse numeric array \"%s\": too few numbers", str); + exit_nicely(1); + } + + while (argNum < allocsize) + array[argNum++] = InvalidOid; + + return array; +} + + +/* + * parseIntArray + * parse a string of possibly-signed numbers separated by spaces + * into an array of ints + * + * This is exactly like parseOidArray, but for integers. + */ +int * +parseIntArray(const char *str, int arraysize) +{ + int *array; + int allocsize, + argNum, + templen; + char temp[32]; + + if (arraysize >= 0) + allocsize = arraysize; + else + { + /* + * Make enough room for input + one extra entry (could be more than + * enough, if there are redundant spaces in the input). + */ + allocsize = 2; + for (const char *s1 = str; *s1; s1++) + { + if (*s1 == ' ') + allocsize++; + } + } + array = pg_malloc_array(int, allocsize); + argNum = 0; + templen = 0; + for (const char *s1 = str;; s1++) + { + char s = *s1; + + if (s == ' ' || s == '\0') + { + if (templen > 0) + { + if (arraysize >= 0 && argNum >= arraysize) + { + pg_log_error("could not parse numeric array \"%s\": too many numbers", str); + exit_nicely(1); + } + temp[templen] = '\0'; + array[argNum++] = atoi(temp); + templen = 0; } if (s == '\0') break; @@ -1169,17 +1269,25 @@ parseOidArray(const char *str, Oid *array, int arraysize) else { if (!(isdigit((unsigned char) s) || s == '-') || - j >= sizeof(temp) - 1) + templen >= sizeof(temp) - 1) { pg_log_error("could not parse numeric array \"%s\": invalid character in number", str); exit_nicely(1); } - temp[j++] = s; + temp[templen++] = s; } } - while (argNum < arraysize) - array[argNum++] = InvalidOid; + if (arraysize >= 0 && argNum != arraysize) + { + pg_log_error("could not parse numeric array \"%s\": too few numbers", str); + exit_nicely(1); + } + + while (argNum < allocsize) + array[argNum++] = 0; + + return array; } diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 9bebf231b7f..87d9f8452fe 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -6204,12 +6204,8 @@ getAggregates(Archive *fout, int *numAggs) if (agginfo[i].aggfn.nargs == 0) agginfo[i].aggfn.argtypes = NULL; else - { - agginfo[i].aggfn.argtypes = (Oid *) pg_malloc(agginfo[i].aggfn.nargs * sizeof(Oid)); - parseOidArray(PQgetvalue(res, i, i_proargtypes), - agginfo[i].aggfn.argtypes, - agginfo[i].aggfn.nargs); - } + agginfo[i].aggfn.argtypes = parseOidArray(PQgetvalue(res, i, i_proargtypes), + agginfo[i].aggfn.nargs); agginfo[i].aggfn.postponed_def = false; /* might get set during sort */ /* Decide whether we want to dump it */ @@ -6436,11 +6432,8 @@ getFuncs(Archive *fout, int *numFuncs) if (finfo[i].nargs == 0) finfo[i].argtypes = NULL; else - { - finfo[i].argtypes = (Oid *) pg_malloc(finfo[i].nargs * sizeof(Oid)); - parseOidArray(PQgetvalue(res, i, i_proargtypes), - finfo[i].argtypes, finfo[i].nargs); - } + finfo[i].argtypes = parseOidArray(PQgetvalue(res, i, i_proargtypes), + finfo[i].nargs); finfo[i].postponed_def = false; /* might get set during sort */ /* Decide whether we want to dump it */ @@ -7747,9 +7740,8 @@ getIndexes(Archive *fout, TableInfo tblinfo[], int numTables) indxinfo[j].indreloptions = pg_strdup(PQgetvalue(res, j, i_indreloptions)); indxinfo[j].indstatcols = pg_strdup(PQgetvalue(res, j, i_indstatcols)); indxinfo[j].indstatvals = pg_strdup(PQgetvalue(res, j, i_indstatvals)); - indxinfo[j].indkeys = (Oid *) pg_malloc(indxinfo[j].indnattrs * sizeof(Oid)); - parseOidArray(PQgetvalue(res, j, i_indkey), - indxinfo[j].indkeys, indxinfo[j].indnattrs); + indxinfo[j].indkeys = parseIntArray(PQgetvalue(res, j, i_indkey), + indxinfo[j].indnattrs); indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't'); indxinfo[j].indisreplident = (PQgetvalue(res, j, i_indisreplident)[0] == 't'); indxinfo[j].parentidx = atooid(PQgetvalue(res, j, i_parentidx)); @@ -12695,12 +12687,10 @@ dumpFunc(Archive *fout, const FuncInfo *finfo) if (protrftypes != NULL && strcmp(protrftypes, "") != 0) { - Oid *typeids = palloc(FUNC_MAX_ARGS * sizeof(Oid)); - int i; + Oid *typeids = parseOidArray(protrftypes, -1); appendPQExpBufferStr(q, " TRANSFORM "); - parseOidArray(protrftypes, typeids, FUNC_MAX_ARGS); - for (i = 0; typeids[i]; i++) + for (int i = 0; typeids[i]; i++) { if (i != 0) appendPQExpBufferStr(q, ", "); @@ -17369,7 +17359,7 @@ dumpConstraint(Archive *fout, const ConstraintInfo *coninfo) coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE"); for (k = 0; k < indxinfo->indnkeyattrs; k++) { - int indkey = (int) indxinfo->indkeys[k]; + int indkey = indxinfo->indkeys[k]; const char *attname; if (indkey == InvalidAttrNumber) @@ -17386,7 +17376,7 @@ dumpConstraint(Archive *fout, const ConstraintInfo *coninfo) for (k = indxinfo->indnkeyattrs; k < indxinfo->indnattrs; k++) { - int indkey = (int) indxinfo->indkeys[k]; + int indkey = indxinfo->indkeys[k]; const char *attname; if (indkey == InvalidAttrNumber) diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h index bcd78414753..902a926a228 100644 --- a/src/bin/pg_dump/pg_dump.h +++ b/src/bin/pg_dump/pg_dump.h @@ -381,7 +381,7 @@ typedef struct _indxInfo char *indstatvals; /* statistic values for columns */ int indnkeyattrs; /* number of index key attributes */ int indnattrs; /* total number of index attributes */ - Oid *indkeys; /* In spite of the name 'indkeys' this field + int *indkeys; /* In spite of the name 'indkeys' this field * contains both key and nonkey attributes */ bool indisclustered; bool indisreplident; @@ -689,7 +689,8 @@ extern PublicationInfo *findPublicationByOid(Oid oid); extern void setExtensionMembership(ExtensionMemberId *extmems, int nextmems); extern ExtensionInfo *findOwningExtension(CatalogId catalogId); -extern void parseOidArray(const char *str, Oid *array, int arraysize); +extern Oid *parseOidArray(const char *str, int arraysize); +extern int *parseIntArray(const char *str, int arraysize); extern void sortDumpableObjects(DumpableObject **objs, int numObjs, DumpId preBoundaryId, DumpId postBoundaryId); diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out index 388097a6957..79af841700a 100644 --- a/src/test/regress/expected/object_address.out +++ b/src/test/regress/expected/object_address.out @@ -42,6 +42,10 @@ ALTER DEFAULT PRIVILEGES FOR ROLE regress_addr_user REVOKE DELETE ON TABLES FROM CREATE TRANSFORM FOR int LANGUAGE SQL ( FROM SQL WITH FUNCTION prsd_lextype(internal), TO SQL WITH FUNCTION int4recv(internal)); +-- make a function that uses it too, mainly to exercise pg_dump +CREATE FUNCTION public.sql_func_with_transform(int) RETURNS int LANGUAGE sql +AS 'select $1 + 1' +TRANSFORM FOR TYPE int; -- suppress warning that depends on wal_level SET client_min_messages = 'ERROR'; CREATE PUBLICATION addr_pub FOR TABLE addr_nsp.gentable; diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql index 2f4f66e3e12..80d21149e3a 100644 --- a/src/test/regress/sql/object_address.sql +++ b/src/test/regress/sql/object_address.sql @@ -45,6 +45,10 @@ ALTER DEFAULT PRIVILEGES FOR ROLE regress_addr_user REVOKE DELETE ON TABLES FROM CREATE TRANSFORM FOR int LANGUAGE SQL ( FROM SQL WITH FUNCTION prsd_lextype(internal), TO SQL WITH FUNCTION int4recv(internal)); +-- make a function that uses it too, mainly to exercise pg_dump +CREATE FUNCTION public.sql_func_with_transform(int) RETURNS int LANGUAGE sql +AS 'select $1 + 1' +TRANSFORM FOR TYPE int; -- suppress warning that depends on wal_level SET client_min_messages = 'ERROR'; CREATE PUBLICATION addr_pub FOR TABLE addr_nsp.gentable;