Skip to content

Commit ad50934

Browse files
committed
Fix alignment and toasting bugs in range types.
A range type whose element type has 'd' alignment must have 'd' alignment itself, else there is no guarantee that the element value can be used in-place. (Because range_deserialize uses att_align_pointer which forcibly aligns the given pointer, violations of this rule did not lead to SIGBUS but rather to garbage data being extracted, as in one of the added regression test cases.) Also, you can't put a toast pointer inside a range datum, since the referenced value could disappear with the range datum still present. For consistency with the handling of arrays and records, I also forced decompression of in-line-compressed bound values. It would work to store them as-is, but our policy is to avoid situations that might result in double compression. Add assorted regression tests for this, and bump catversion because of fixes to built-in pg_type entries. Also some marginal cleanup of inconsistent/unnecessary error checks.
1 parent 4165d5b commit ad50934

File tree

8 files changed

+215
-130
lines changed

8 files changed

+215
-130
lines changed

src/backend/commands/typecmds.c

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1167,8 +1167,6 @@ DefineRange(CreateRangeStmt *stmt)
11671167
Oid typoid;
11681168
Oid rangeArrayOid;
11691169
List *parameters = stmt->params;
1170-
1171-
ListCell *lc;
11721170
List *rangeSubOpclassName = NIL;
11731171
List *rangeSubtypeDiffName = NIL;
11741172
List *rangeCollationName = NIL;
@@ -1178,8 +1176,12 @@ DefineRange(CreateRangeStmt *stmt)
11781176
regproc rangeSubOpclass = InvalidOid;
11791177
regproc rangeCanonical = InvalidOid;
11801178
regproc rangeSubtypeDiff = InvalidOid;
1181-
1179+
int16 subtyplen;
1180+
bool subtypbyval;
1181+
char subtypalign;
1182+
char alignment;
11821183
AclResult aclresult;
1184+
ListCell *lc;
11831185

11841186
/* Convert list of names to a name and namespace */
11851187
typeNamespace = QualifiedNameGetCreationNamespace(stmt->typeName,
@@ -1314,14 +1316,21 @@ DefineRange(CreateRangeStmt *stmt)
13141316
else if (rangeCollationName != NIL)
13151317
ereport(ERROR,
13161318
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
1317-
errmsg("range collation provided but subtype does not support collation")));
1319+
errmsg("range collation specified but subtype does not support collation")));
13181320

13191321
rangeSubOpclass = findRangeSubOpclass(rangeSubOpclassName, rangeSubtype);
13201322

13211323
if (rangeSubtypeDiffName != NIL)
1322-
rangeSubtypeDiff = findRangeSubtypeDiffFunction(
1323-
rangeSubtypeDiffName, rangeSubtype);
1324+
rangeSubtypeDiff = findRangeSubtypeDiffFunction(rangeSubtypeDiffName,
1325+
rangeSubtype);
13241326

1327+
get_typlenbyvalalign(rangeSubtype,
1328+
&subtyplen, &subtypbyval, &subtypalign);
1329+
1330+
/* alignment must be 'i' or 'd' for ranges */
1331+
alignment = (subtypalign == 'd') ? 'd' : 'i';
1332+
1333+
/* Allocate OID for array type */
13251334
rangeArrayOid = AssignTypeArrayOid();
13261335

13271336
/* Create the pg_type entry */
@@ -1332,7 +1341,7 @@ DefineRange(CreateRangeStmt *stmt)
13321341
InvalidOid, /* relation oid (n/a here) */
13331342
0, /* relation kind (ditto) */
13341343
GetUserId(), /* owner's ID */
1335-
-1, /* internal size */
1344+
-1, /* internal size (always varlena) */
13361345
TYPTYPE_RANGE, /* type-type (range type) */
13371346
TYPCATEGORY_RANGE, /* type-category (range type) */
13381347
false, /* range types are never preferred */
@@ -1343,16 +1352,16 @@ DefineRange(CreateRangeStmt *stmt)
13431352
F_RANGE_SEND, /* send procedure */
13441353
InvalidOid, /* typmodin procedure - none */
13451354
InvalidOid, /* typmodout procedure - none */
1346-
rangeAnalyze, /* analyze procedure - default */
1347-
InvalidOid, /* element type ID */
1355+
rangeAnalyze, /* analyze procedure */
1356+
InvalidOid, /* element type ID - none */
13481357
false, /* this is not an array type */
13491358
rangeArrayOid, /* array type we are about to create */
13501359
InvalidOid, /* base type ID (only for domains) */
13511360
NULL, /* never a default type value */
13521361
NULL, /* binary default isn't sent either */
13531362
false, /* never passed by value */
1354-
'i', /* int alignment */
1355-
'x', /* TOAST strategy always plain */
1363+
alignment, /* alignment */
1364+
'x', /* TOAST strategy (always extended) */
13561365
-1, /* typMod (Domains only) */
13571366
0, /* Array dimensions of typbasetype */
13581367
false, /* Type NOT NULL */
@@ -1392,7 +1401,7 @@ DefineRange(CreateRangeStmt *stmt)
13921401
NULL, /* never a default type value */
13931402
NULL, /* binary default isn't sent either */
13941403
false, /* never passed by value */
1395-
'i', /* align 'i' */
1404+
alignment, /* alignment - same as range's */
13961405
'x', /* ARRAY is always toastable */
13971406
-1, /* typMod (Domains only) */
13981407
0, /* Array dimensions of typbasetype */
@@ -1401,6 +1410,7 @@ DefineRange(CreateRangeStmt *stmt)
14011410

14021411
pfree(rangeArrayName);
14031412

1413+
/* And create the constructor functions for this range type */
14041414
makeRangeConstructor(typeName, typeNamespace, typoid, rangeSubtype);
14051415
}
14061416

0 commit comments

Comments
 (0)