aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/nodes/makefuncs.c9
-rw-r--r--src/backend/optimizer/util/clauses.c3
-rw-r--r--src/backend/parser/parse_coerce.c38
-rw-r--r--src/backend/parser/parse_type.c31
-rw-r--r--src/include/nodes/primnodes.h5
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
{