diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/nodes/makefuncs.c | 9 | ||||
-rw-r--r-- | src/backend/optimizer/util/clauses.c | 3 | ||||
-rw-r--r-- | src/backend/parser/parse_coerce.c | 38 | ||||
-rw-r--r-- | src/backend/parser/parse_type.c | 31 | ||||
-rw-r--r-- | src/include/nodes/primnodes.h | 5 |
5 files changed, 55 insertions, 31 deletions
diff --git a/src/backend/nodes/makefuncs.c b/src/backend/nodes/makefuncs.c index 4be89f63ae0..437abad06af 100644 --- a/src/backend/nodes/makefuncs.c +++ b/src/backend/nodes/makefuncs.c @@ -17,6 +17,7 @@ #include "catalog/pg_class.h" #include "catalog/pg_type.h" +#include "fmgr.h" #include "nodes/makefuncs.h" #include "nodes/nodeFuncs.h" #include "utils/lsyscache.h" @@ -302,6 +303,14 @@ makeConst(Oid consttype, { Const *cnst = makeNode(Const); + /* + * If it's a varlena value, force it to be in non-expanded (non-toasted) + * format; this avoids any possible dependency on external values and + * improves consistency of representation, which is important for equal(). + */ + if (!constisnull && constlen == -1) + constvalue = PointerGetDatum(PG_DETOAST_DATUM(constvalue)); + cnst->consttype = consttype; cnst->consttypmod = consttypmod; cnst->constcollid = constcollid; diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index c72dbef1c83..e6d83d4fd93 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -4655,7 +4655,8 @@ evaluate_expr(Expr *expr, Oid result_type, int32 result_typmod, * * Also, if it's varlena, forcibly detoast it. This protects us against * storing TOAST pointers into plans that might outlive the referenced - * data. + * data. (makeConst would handle detoasting anyway, but it's worth a few + * extra lines here so that we can do the copy and detoast in one step.) */ if (!const_is_null) { diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c index f6e7be4e710..589183c277e 100644 --- a/src/backend/parser/parse_coerce.c +++ b/src/backend/parser/parse_coerce.c @@ -26,6 +26,7 @@ #include "parser/parse_relation.h" #include "parser/parse_type.h" #include "utils/builtins.h" +#include "utils/datum.h" #include "utils/lsyscache.h" #include "utils/syscache.h" #include "utils/typcache.h" @@ -308,6 +309,43 @@ coerce_type(ParseState *pstate, Node *node, NULL, inputTypeMod); + /* + * If it's a varlena value, force it to be in non-expanded + * (non-toasted) format; this avoids any possible dependency on + * external values and improves consistency of representation. + */ + if (!con->constisnull && newcon->constlen == -1) + newcon->constvalue = + PointerGetDatum(PG_DETOAST_DATUM(newcon->constvalue)); + +#ifdef RANDOMIZE_ALLOCATED_MEMORY + + /* + * For pass-by-reference data types, repeat the conversion to see if + * the input function leaves any uninitialized bytes in the result. We + * can only detect that reliably if RANDOMIZE_ALLOCATED_MEMORY is + * enabled, so we don't bother testing otherwise. The reason we don't + * want any instability in the input function is that comparison of + * Const nodes relies on bytewise comparison of the datums, so if the + * input function leaves garbage then subexpressions that should be + * identical may not get recognized as such. See pgsql-hackers + * discussion of 2008-04-04. + */ + if (!con->constisnull && !newcon->constbyval) + { + Datum val2; + + val2 = stringTypeDatum(baseType, + DatumGetCString(con->constvalue), + inputTypeMod); + if (newcon->constlen == -1) + val2 = PointerGetDatum(PG_DETOAST_DATUM(val2)); + if (!datumIsEqual(newcon->constvalue, val2, false, newcon->constlen)) + elog(WARNING, "type %s has unstable input conversion for \"%s\"", + typeTypeName(baseType), DatumGetCString(con->constvalue)); + } +#endif + cancel_parser_errposition_callback(&pcbstate); result = (Node *) newcon; diff --git a/src/backend/parser/parse_type.c b/src/backend/parser/parse_type.c index 661663994ee..9db3553d80a 100644 --- a/src/backend/parser/parse_type.c +++ b/src/backend/parser/parse_type.c @@ -23,7 +23,6 @@ #include "parser/parse_type.h" #include "utils/array.h" #include "utils/builtins.h" -#include "utils/datum.h" #include "utils/lsyscache.h" #include "utils/syscache.h" @@ -639,36 +638,8 @@ stringTypeDatum(Type tp, char *string, int32 atttypmod) Form_pg_type typform = (Form_pg_type) GETSTRUCT(tp); Oid typinput = typform->typinput; Oid typioparam = getTypeIOParam(tp); - Datum result; - result = OidInputFunctionCall(typinput, string, - typioparam, atttypmod); - -#ifdef RANDOMIZE_ALLOCATED_MEMORY - - /* - * For pass-by-reference data types, repeat the conversion to see if the - * input function leaves any uninitialized bytes in the result. We can - * only detect that reliably if RANDOMIZE_ALLOCATED_MEMORY is enabled, so - * we don't bother testing otherwise. The reason we don't want any - * instability in the input function is that comparison of Const nodes - * relies on bytewise comparison of the datums, so if the input function - * leaves garbage then subexpressions that should be identical may not get - * recognized as such. See pgsql-hackers discussion of 2008-04-04. - */ - if (string && !typform->typbyval) - { - Datum result2; - - result2 = OidInputFunctionCall(typinput, string, - typioparam, atttypmod); - if (!datumIsEqual(result, result2, typform->typbyval, typform->typlen)) - elog(WARNING, "type %s has unstable input conversion for \"%s\"", - NameStr(typform->typname), string); - } -#endif - - return result; + return OidInputFunctionCall(typinput, string, typioparam, atttypmod); } /* given a typeid, return the type's typrelid (associated relation, if any) */ diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h index 60c1ca2c8dc..c8b1f907a8f 100644 --- a/src/include/nodes/primnodes.h +++ b/src/include/nodes/primnodes.h @@ -165,6 +165,11 @@ typedef struct Var /* * Const + * + * Note: for varlena data types, we make a rule that a Const node's value + * must be in non-extended form (4-byte header, no compression or external + * references). This ensures that the Const node is self-contained and makes + * it more likely that equal() will see logically identical values as equal. */ typedef struct Const { |