Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 670c0a1

Browse files
committed
Weaken type-OID-matching checks in array_recv and record_recv.
Rather than always insisting on an exact match of the type OID in the data to the element type or column type we expect, complain only when both OIDs fall within the manually-assigned range. This acknowledges the reality that user-defined types don't have stable OIDs, while still preserving some of the mistake-detection value of the old test. (It's not entirely clear whether to error if one OID is manually assigned and the other isn't. But perhaps that case could arise in cross-version cases where a former extension type has been imported into core, so I let it pass.) This change allows us to remove the prohibition on binary transfer of user-defined arrays and composites in the recently-landed support for binary logical replication (commit 9de77b5). We can just unconditionally drop that check, since if the client has asked for binary transfer it must be >= v14 and must have this change. Discussion: https://postgr.es/m/CADK3HH+R3xMn=8t3Ct+uD+qJ1KD=Hbif5NFMJ+d5DkoCzp6Vgw@mail.gmail.com
1 parent 606c384 commit 670c0a1

File tree

3 files changed

+51
-23
lines changed

3 files changed

+51
-23
lines changed

src/backend/replication/logical/proto.c

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -494,22 +494,9 @@ logicalrep_write_tuple(StringInfo out, Relation rel, HeapTuple tuple, bool binar
494494
typclass = (Form_pg_type) GETSTRUCT(typtup);
495495

496496
/*
497-
* Choose whether to send in binary. Obviously, the option must be
498-
* requested and the type must have a send function. Also, if the
499-
* type is not built-in then it must not be a composite or array type.
500-
* Such types contain type OIDs, which will likely not match at the
501-
* receiver if it's not a built-in type.
502-
*
503-
* XXX this could be relaxed if we changed record_recv and array_recv
504-
* to be less picky.
505-
*
506-
* XXX this fails to apply the restriction to domains over such types.
497+
* Send in binary if requested and type has suitable send function.
507498
*/
508-
if (binary &&
509-
OidIsValid(typclass->typsend) &&
510-
(att->atttypid < FirstGenbkiObjectId ||
511-
(typclass->typtype != TYPTYPE_COMPOSITE &&
512-
typclass->typelem == InvalidOid)))
499+
if (binary && OidIsValid(typclass->typsend))
513500
{
514501
bytea *outputbytes;
515502
int len;

src/backend/utils/adt/arrayfuncs.c

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1308,13 +1308,34 @@ array_recv(PG_FUNCTION_ARGS)
13081308
(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
13091309
errmsg("invalid array flags")));
13101310

1311+
/* Check element type recorded in the data */
13111312
element_type = pq_getmsgint(buf, sizeof(Oid));
1313+
1314+
/*
1315+
* From a security standpoint, it doesn't matter whether the input's
1316+
* element type matches what we expect: the element type's receive
1317+
* function has to be robust enough to cope with invalid data. However,
1318+
* from a user-friendliness standpoint, it's nicer to complain about type
1319+
* mismatches than to throw "improper binary format" errors. But there's
1320+
* a problem: only built-in types have OIDs that are stable enough to
1321+
* believe that a mismatch is a real issue. So complain only if both OIDs
1322+
* are in the built-in range. Otherwise, carry on with the element type
1323+
* we "should" be getting.
1324+
*/
13121325
if (element_type != spec_element_type)
13131326
{
1314-
/* XXX Can we allow taking the input element type in any cases? */
1315-
ereport(ERROR,
1316-
(errcode(ERRCODE_DATATYPE_MISMATCH),
1317-
errmsg("wrong element type")));
1327+
if (element_type < FirstGenbkiObjectId &&
1328+
spec_element_type < FirstGenbkiObjectId)
1329+
ereport(ERROR,
1330+
(errcode(ERRCODE_DATATYPE_MISMATCH),
1331+
errmsg("binary data has array element type %u (%s) instead of expected %u (%s)",
1332+
element_type,
1333+
format_type_extended(element_type, -1,
1334+
FORMAT_TYPE_ALLOW_INVALID),
1335+
spec_element_type,
1336+
format_type_extended(spec_element_type, -1,
1337+
FORMAT_TYPE_ALLOW_INVALID))));
1338+
element_type = spec_element_type;
13181339
}
13191340

13201341
for (i = 0; i < ndim; i++)

src/backend/utils/adt/rowtypes.c

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -551,13 +551,33 @@ record_recv(PG_FUNCTION_ARGS)
551551
continue;
552552
}
553553

554-
/* Verify column datatype */
554+
/* Check column type recorded in the data */
555555
coltypoid = pq_getmsgint(buf, sizeof(Oid));
556-
if (coltypoid != column_type)
556+
557+
/*
558+
* From a security standpoint, it doesn't matter whether the input's
559+
* column type matches what we expect: the column type's receive
560+
* function has to be robust enough to cope with invalid data.
561+
* However, from a user-friendliness standpoint, it's nicer to
562+
* complain about type mismatches than to throw "improper binary
563+
* format" errors. But there's a problem: only built-in types have
564+
* OIDs that are stable enough to believe that a mismatch is a real
565+
* issue. So complain only if both OIDs are in the built-in range.
566+
* Otherwise, carry on with the column type we "should" be getting.
567+
*/
568+
if (coltypoid != column_type &&
569+
coltypoid < FirstGenbkiObjectId &&
570+
column_type < FirstGenbkiObjectId)
557571
ereport(ERROR,
558572
(errcode(ERRCODE_DATATYPE_MISMATCH),
559-
errmsg("wrong data type: %u, expected %u",
560-
coltypoid, column_type)));
573+
errmsg("binary data has type %u (%s) instead of expected %u (%s) in record column %d",
574+
coltypoid,
575+
format_type_extended(coltypoid, -1,
576+
FORMAT_TYPE_ALLOW_INVALID),
577+
column_type,
578+
format_type_extended(column_type, -1,
579+
FORMAT_TYPE_ALLOW_INVALID),
580+
i + 1)));
561581

562582
/* Get and check the item length */
563583
itemlen = pq_getmsgint(buf, 4);

0 commit comments

Comments
 (0)