diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2011-11-14 21:42:04 -0500 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2011-11-14 21:42:04 -0500 |
commit | ad50934eaadb626de682defe0ad270bbf31e92a2 (patch) | |
tree | b6bfb3e949b397de41e7278538c62e11460fa575 /src/backend/commands/typecmds.c | |
parent | 4165d5b6d7d2e399edbc6d027039358794aa8f04 (diff) | |
download | postgresql-ad50934eaadb626de682defe0ad270bbf31e92a2.tar.gz postgresql-ad50934eaadb626de682defe0ad270bbf31e92a2.zip |
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.
Diffstat (limited to 'src/backend/commands/typecmds.c')
-rw-r--r-- | src/backend/commands/typecmds.c | 34 |
1 files changed, 22 insertions, 12 deletions
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index c2f1160e1f5..a1628bc0985 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -1167,8 +1167,6 @@ DefineRange(CreateRangeStmt *stmt) Oid typoid; Oid rangeArrayOid; List *parameters = stmt->params; - - ListCell *lc; List *rangeSubOpclassName = NIL; List *rangeSubtypeDiffName = NIL; List *rangeCollationName = NIL; @@ -1178,8 +1176,12 @@ DefineRange(CreateRangeStmt *stmt) regproc rangeSubOpclass = InvalidOid; regproc rangeCanonical = InvalidOid; regproc rangeSubtypeDiff = InvalidOid; - + int16 subtyplen; + bool subtypbyval; + char subtypalign; + char alignment; AclResult aclresult; + ListCell *lc; /* Convert list of names to a name and namespace */ typeNamespace = QualifiedNameGetCreationNamespace(stmt->typeName, @@ -1314,14 +1316,21 @@ DefineRange(CreateRangeStmt *stmt) else if (rangeCollationName != NIL) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("range collation provided but subtype does not support collation"))); + errmsg("range collation specified but subtype does not support collation"))); rangeSubOpclass = findRangeSubOpclass(rangeSubOpclassName, rangeSubtype); if (rangeSubtypeDiffName != NIL) - rangeSubtypeDiff = findRangeSubtypeDiffFunction( - rangeSubtypeDiffName, rangeSubtype); + rangeSubtypeDiff = findRangeSubtypeDiffFunction(rangeSubtypeDiffName, + rangeSubtype); + get_typlenbyvalalign(rangeSubtype, + &subtyplen, &subtypbyval, &subtypalign); + + /* alignment must be 'i' or 'd' for ranges */ + alignment = (subtypalign == 'd') ? 'd' : 'i'; + + /* Allocate OID for array type */ rangeArrayOid = AssignTypeArrayOid(); /* Create the pg_type entry */ @@ -1332,7 +1341,7 @@ DefineRange(CreateRangeStmt *stmt) InvalidOid, /* relation oid (n/a here) */ 0, /* relation kind (ditto) */ GetUserId(), /* owner's ID */ - -1, /* internal size */ + -1, /* internal size (always varlena) */ TYPTYPE_RANGE, /* type-type (range type) */ TYPCATEGORY_RANGE, /* type-category (range type) */ false, /* range types are never preferred */ @@ -1343,16 +1352,16 @@ DefineRange(CreateRangeStmt *stmt) F_RANGE_SEND, /* send procedure */ InvalidOid, /* typmodin procedure - none */ InvalidOid, /* typmodout procedure - none */ - rangeAnalyze, /* analyze procedure - default */ - InvalidOid, /* element type ID */ + rangeAnalyze, /* analyze procedure */ + InvalidOid, /* element type ID - none */ false, /* this is not an array type */ rangeArrayOid, /* array type we are about to create */ InvalidOid, /* base type ID (only for domains) */ NULL, /* never a default type value */ NULL, /* binary default isn't sent either */ false, /* never passed by value */ - 'i', /* int alignment */ - 'x', /* TOAST strategy always plain */ + alignment, /* alignment */ + 'x', /* TOAST strategy (always extended) */ -1, /* typMod (Domains only) */ 0, /* Array dimensions of typbasetype */ false, /* Type NOT NULL */ @@ -1392,7 +1401,7 @@ DefineRange(CreateRangeStmt *stmt) NULL, /* never a default type value */ NULL, /* binary default isn't sent either */ false, /* never passed by value */ - 'i', /* align 'i' */ + alignment, /* alignment - same as range's */ 'x', /* ARRAY is always toastable */ -1, /* typMod (Domains only) */ 0, /* Array dimensions of typbasetype */ @@ -1401,6 +1410,7 @@ DefineRange(CreateRangeStmt *stmt) pfree(rangeArrayName); + /* And create the constructor functions for this range type */ makeRangeConstructor(typeName, typeNamespace, typoid, rangeSubtype); } |