From 43bfffcbc39f540c10ef62dd8afe77e0352bc89b Mon Sep 17 00:00:00 2001 From: Franck Verrot Date: Sun, 28 Jun 2015 11:03:31 +0200 Subject: [PATCH] Provide more into the varchar constraint validator --- src/backend/catalog/heap.c | 3 +- src/backend/commands/prepare.c | 3 +- src/backend/commands/tablecmds.c | 9 ++++-- src/backend/optimizer/prep/preptlist.c | 4 ++- src/backend/parser/parse_clause.c | 10 +++--- src/backend/parser/parse_coerce.c | 58 ++++++++++++++++++++++------------ src/backend/parser/parse_expr.c | 9 ++++-- src/backend/parser/parse_func.c | 16 ++++++---- src/backend/parser/parse_node.c | 9 ++++-- src/backend/parser/parse_target.c | 9 ++++-- src/backend/rewrite/rewriteHandler.c | 9 ++++-- src/backend/rewrite/rewriteManip.c | 3 +- src/backend/utils/adt/varchar.c | 8 +++-- src/include/parser/parse_coerce.h | 7 ++-- src/pl/plpgsql/src/pl_exec.c | 6 ++-- 15 files changed, 106 insertions(+), 57 deletions(-) diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index d04e94d..19c7a6d 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -2584,7 +2584,8 @@ cookDefault(ParseState *pstate, atttypid, atttypmod, COERCION_ASSIGNMENT, COERCE_IMPLICIT_CAST, - -1); + -1, + attname); if (expr == NULL) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c index fb33d30..99a1bb7 100644 --- a/src/backend/commands/prepare.c +++ b/src/backend/commands/prepare.c @@ -362,7 +362,8 @@ EvaluateParams(PreparedStatement *pstmt, List *params, expected_type_id, -1, COERCION_ASSIGNMENT, COERCE_IMPLICIT_CAST, - -1); + -1, + NULL); if (expr == NULL) ereport(ERROR, diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 84dbee0..1dc5f09 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -4919,7 +4919,8 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel, typmod, COERCION_ASSIGNMENT, COERCE_IMPLICIT_CAST, - -1); + -1, + NULL); if (defval == NULL) /* should not happen */ elog(ERROR, "failed to coerce base type to domain"); } @@ -7886,7 +7887,8 @@ ATPrepAlterColumnType(List **wqueue, targettype, targettypmod, COERCION_ASSIGNMENT, COERCE_IMPLICIT_CAST, - -1); + -1, + colName); if (transform == NULL) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), @@ -8060,7 +8062,8 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel, targettype, targettypmod, COERCION_ASSIGNMENT, COERCE_IMPLICIT_CAST, - -1); + -1, + NULL); if (defaultexpr == NULL) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), diff --git a/src/backend/optimizer/prep/preptlist.c b/src/backend/optimizer/prep/preptlist.c index 6b0c689..bc5bd62 100644 --- a/src/backend/optimizer/prep/preptlist.c +++ b/src/backend/optimizer/prep/preptlist.c @@ -276,6 +276,7 @@ expand_targetlist(List *tlist, int command_type, Oid attcollation = att_tup->attcollation; Node *new_expr; + //RelationGetRelationName switch (command_type) { case CMD_INSERT: @@ -294,7 +295,8 @@ expand_targetlist(List *tlist, int command_type, COERCE_IMPLICIT_CAST, -1, false, - false); + false, + NULL); } else { diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c index e90e1d6..3b94fe1 100644 --- a/src/backend/parser/parse_clause.c +++ b/src/backend/parser/parse_clause.c @@ -1232,7 +1232,7 @@ buildMergedJoinVar(ParseState *pstate, JoinType jointype, if (l_colvar->vartype != outcoltype) l_node = coerce_type(pstate, (Node *) l_colvar, l_colvar->vartype, outcoltype, outcoltypmod, - COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, -1); + COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, -1, NULL); else if (l_colvar->vartypmod != outcoltypmod) l_node = (Node *) makeRelabelType((Expr *) l_colvar, outcoltype, outcoltypmod, @@ -1244,7 +1244,7 @@ buildMergedJoinVar(ParseState *pstate, JoinType jointype, if (r_colvar->vartype != outcoltype) r_node = coerce_type(pstate, (Node *) r_colvar, r_colvar->vartype, outcoltype, outcoltypmod, - COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, -1); + COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, -1, NULL); else if (r_colvar->vartypmod != outcoltypmod) r_node = (Node *) makeRelabelType((Expr *) r_colvar, outcoltype, outcoltypmod, @@ -2871,7 +2871,8 @@ addTargetToSortList(ParseState *pstate, TargetEntry *tle, restype, TEXTOID, -1, COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, - -1); + -1, + NULL); restype = TEXTOID; } @@ -3014,7 +3015,8 @@ addTargetToGroupList(ParseState *pstate, TargetEntry *tle, restype, TEXTOID, -1, COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, - -1); + -1, + NULL); restype = TEXTOID; } diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c index f6e7be4..184dcab 100644 --- a/src/backend/parser/parse_coerce.c +++ b/src/backend/parser/parse_coerce.c @@ -34,14 +34,15 @@ static Node *coerce_type_typmod(Node *node, Oid targetTypeId, int32 targetTypMod, CoercionForm cformat, int location, - bool isExplicit, bool hideInputCoercion); + bool isExplicit, bool hideInputCoercion, char *colname); static void hide_coercion_node(Node *node); static Node *build_coercion_expression(Node *node, CoercionPathType pathtype, Oid funcId, Oid targetTypeId, int32 targetTypMod, CoercionForm cformat, int location, - bool isExplicit); + bool isExplicit, + char *colname); static Node *coerce_record_to_complex(ParseState *pstate, Node *node, Oid targetTypeId, CoercionContext ccontext, @@ -77,7 +78,8 @@ coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype, Oid targettype, int32 targettypmod, CoercionContext ccontext, CoercionForm cformat, - int location) + int location, + char *colname) { Node *result; Node *origexpr; @@ -100,7 +102,7 @@ coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype, result = coerce_type(pstate, expr, exprtype, targettype, targettypmod, - ccontext, cformat, location); + ccontext, cformat, location, colname); /* * If the target is a fixed-length type, it may need a length coercion as @@ -111,7 +113,8 @@ coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype, targettype, targettypmod, cformat, location, (cformat != COERCE_IMPLICIT_CAST), - (result != expr && !IsA(result, Const))); + (result != expr && !IsA(result, Const)), + colname); if (expr != origexpr) { @@ -154,7 +157,7 @@ coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype, Node * coerce_type(ParseState *pstate, Node *node, Oid inputTypeId, Oid targetTypeId, int32 targetTypeMod, - CoercionContext ccontext, CoercionForm cformat, int location) + CoercionContext ccontext, CoercionForm cformat, int location, char *colname) { Node *result; CoercionPathType pathtype; @@ -317,7 +320,7 @@ coerce_type(ParseState *pstate, Node *node, result = coerce_to_domain(result, baseTypeId, baseTypeMod, targetTypeId, - cformat, location, false, false); + cformat, location, false, false, colname); ReleaseSysCache(baseType); @@ -353,7 +356,7 @@ coerce_type(ParseState *pstate, Node *node, newcoll->arg = (Expr *) coerce_type(pstate, (Node *) coll->arg, inputTypeId, targetTypeId, targetTypeMod, - ccontext, cformat, location); + ccontext, cformat, location, colname); newcoll->collOid = coll->collOid; newcoll->location = coll->location; return (Node *) newcoll; @@ -380,7 +383,7 @@ coerce_type(ParseState *pstate, Node *node, result = build_coercion_expression(node, pathtype, funcId, baseTypeId, baseTypeMod, cformat, location, - (cformat != COERCE_IMPLICIT_CAST)); + (cformat != COERCE_IMPLICIT_CAST), colname); /* * If domain, coerce to the domain type and relabel with domain @@ -391,8 +394,8 @@ coerce_type(ParseState *pstate, Node *node, result = coerce_to_domain(result, baseTypeId, baseTypeMod, targetTypeId, cformat, location, true, - exprIsLengthCoercion(result, - NULL)); + exprIsLengthCoercion(result, NULL), + colname); } else { @@ -406,7 +409,7 @@ coerce_type(ParseState *pstate, Node *node, * then we won't need a RelabelType node. */ result = coerce_to_domain(node, InvalidOid, -1, targetTypeId, - cformat, location, false, false); + cformat, location, false, false, colname); if (result == node) { /* @@ -610,7 +613,7 @@ Node * coerce_to_domain(Node *arg, Oid baseTypeId, int32 baseTypeMod, Oid typeId, CoercionForm cformat, int location, bool hideInputCoercion, - bool lengthCoercionDone) + bool lengthCoercionDone, char *colname) { CoerceToDomain *result; @@ -645,7 +648,7 @@ coerce_to_domain(Node *arg, Oid baseTypeId, int32 baseTypeMod, Oid typeId, arg = coerce_type_typmod(arg, baseTypeId, baseTypeMod, COERCE_IMPLICIT_CAST, location, (cformat != COERCE_IMPLICIT_CAST), - false); + false, colname); } /* @@ -689,7 +692,7 @@ coerce_to_domain(Node *arg, Oid baseTypeId, int32 baseTypeMod, Oid typeId, static Node * coerce_type_typmod(Node *node, Oid targetTypeId, int32 targetTypMod, CoercionForm cformat, int location, - bool isExplicit, bool hideInputCoercion) + bool isExplicit, bool hideInputCoercion, char *colname) { CoercionPathType pathtype; Oid funcId; @@ -712,7 +715,8 @@ coerce_type_typmod(Node *node, Oid targetTypeId, int32 targetTypMod, node = build_coercion_expression(node, pathtype, funcId, targetTypeId, targetTypMod, cformat, location, - isExplicit); + isExplicit, + colname); } return node; @@ -762,7 +766,8 @@ build_coercion_expression(Node *node, Oid funcId, Oid targetTypeId, int32 targetTypMod, CoercionForm cformat, int location, - bool isExplicit) + bool isExplicit, + char *colname) { int nargs = 0; @@ -834,6 +839,17 @@ build_coercion_expression(Node *node, args = lappend(args, cons); } + /* Pass it the column name for eventual display */ + cons = makeConst(CSTRINGOID, + -1, + InvalidOid, + strlen(colname), + CStringGetDatum(colname), + false, + true); + + args = lappend(args, cons); + fexpr = makeFuncExpr(funcId, targetTypeId, args, InvalidOid, InvalidOid, cformat); fexpr->location = location; @@ -974,7 +990,7 @@ coerce_record_to_complex(ParseState *pstate, Node *node, tupdesc->attrs[i]->atttypmod, ccontext, COERCE_IMPLICIT_CAST, - -1); + -1, NULL); if (cexpr == NULL) ereport(ERROR, (errcode(ERRCODE_CANNOT_COERCE), @@ -1034,7 +1050,7 @@ coerce_to_boolean(ParseState *pstate, Node *node, BOOLOID, -1, COERCION_ASSIGNMENT, COERCE_IMPLICIT_CAST, - -1); + -1, NULL); if (newnode == NULL) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), @@ -1081,7 +1097,7 @@ coerce_to_specific_type(ParseState *pstate, Node *node, targetTypeId, -1, COERCION_ASSIGNMENT, COERCE_IMPLICIT_CAST, - -1); + -1, NULL); if (newnode == NULL) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), @@ -1281,7 +1297,7 @@ coerce_to_common_type(ParseState *pstate, Node *node, return node; /* no work */ if (can_coerce_type(1, &inputTypeId, &targetTypeId, COERCION_IMPLICIT)) node = coerce_type(pstate, node, inputTypeId, targetTypeId, -1, - COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, -1); + COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, -1, NULL); else ereport(ERROR, (errcode(ERRCODE_CANNOT_COERCE), diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index 0ff46dd..f724efc 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -2007,7 +2007,8 @@ transformArrayExpr(ParseState *pstate, A_ArrayExpr *a, typmod, COERCION_EXPLICIT, COERCE_EXPLICIT_CAST, - -1); + -1, + NULL); if (newe == NULL) ereport(ERROR, (errcode(ERRCODE_CANNOT_COERCE), @@ -2308,7 +2309,8 @@ transformXmlSerialize(ParseState *pstate, XmlSerialize *xs) TEXTOID, targetType, targetTypmod, COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, - -1); + -1, + NULL); if (result == NULL) ereport(ERROR, (errcode(ERRCODE_CANNOT_COERCE), @@ -2520,7 +2522,8 @@ transformTypeCast(ParseState *pstate, TypeCast *tc) targetType, targetTypmod, COERCION_EXPLICIT, COERCE_EXPLICIT_CAST, - location); + location, + NULL); if (result == NULL) ereport(ERROR, (errcode(ERRCODE_CANNOT_COERCE), diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c index fa9761b..b3d0c54 100644 --- a/src/backend/parser/parse_func.c +++ b/src/backend/parser/parse_func.c @@ -258,7 +258,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, */ return coerce_type(pstate, linitial(fargs), actual_arg_types[0], rettype, -1, - COERCION_EXPLICIT, COERCE_EXPLICIT_CALL, location); + COERCION_EXPLICIT, COERCE_EXPLICIT_CALL, location, NULL); } else if (fdresult == FUNCDETAIL_NORMAL) { @@ -898,7 +898,7 @@ ParseTableSample(ParseState *pstate, char *samplemethod, Node *repeatable, parser_errposition(pstate, exprLocation(inarg)))); arg = coerce_type(pstate, arg, argtype, init_arg_types[nargs], -1, - COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, -1); + COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, -1, NULL); } fargs = lappend(fargs, arg); @@ -1788,7 +1788,8 @@ unify_hypothetical_args(ParseState *pstate, commontype, -1, COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, - -1); + -1, + NULL); actual_arg_types[i] = commontype; args[aargpos] = coerce_type(pstate, args[aargpos], @@ -1796,7 +1797,8 @@ unify_hypothetical_args(ParseState *pstate, commontype, -1, COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, - -1); + -1, + NULL); actual_arg_types[aargpos] = commontype; } @@ -1852,7 +1854,8 @@ make_fn_arguments(ParseState *pstate, declared_arg_types[i], -1, COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, - -1); + -1, + NULL); na->arg = (Expr *) node; } else @@ -1863,7 +1866,8 @@ make_fn_arguments(ParseState *pstate, declared_arg_types[i], -1, COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, - -1); + -1, + NULL); lfirst(current_fargs) = node; } } diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c index 4130cbf..52e3ec1 100644 --- a/src/backend/parser/parse_node.c +++ b/src/backend/parser/parse_node.c @@ -349,7 +349,8 @@ transformArraySubscripts(ParseState *pstate, INT4OID, -1, COERCION_ASSIGNMENT, COERCE_IMPLICIT_CAST, - -1); + -1, + NULL); if (subexpr == NULL) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), @@ -376,7 +377,8 @@ transformArraySubscripts(ParseState *pstate, INT4OID, -1, COERCION_ASSIGNMENT, COERCE_IMPLICIT_CAST, - -1); + -1, + NULL); if (subexpr == NULL) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), @@ -400,7 +402,8 @@ transformArraySubscripts(ParseState *pstate, typeneeded, arrayTypMod, COERCION_ASSIGNMENT, COERCE_IMPLICIT_CAST, - -1); + -1, + NULL); if (newFrom == NULL) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c index 1b3fcd6..c14bd5c 100644 --- a/src/backend/parser/parse_target.c +++ b/src/backend/parser/parse_target.c @@ -516,7 +516,8 @@ transformAssignedExpr(ParseState *pstate, attrtype, attrtypmod, COERCION_ASSIGNMENT, COERCE_IMPLICIT_CAST, - -1); + -1, + colname); if (expr == NULL) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), @@ -764,7 +765,8 @@ transformAssignmentIndirection(ParseState *pstate, targetTypeId, targetTypMod, COERCION_ASSIGNMENT, COERCE_IMPLICIT_CAST, - -1); + -1, + "foo indirection"); if (result == NULL) { if (targetIsArray) @@ -866,7 +868,8 @@ transformAssignmentSubscripts(ParseState *pstate, targetTypeId, targetTypMod, COERCION_ASSIGNMENT, COERCE_IMPLICIT_CAST, - -1); + -1, + "foo subscript"); /* can fail if we had int2vector/oidvector, but not for true domains */ if (result == NULL) ereport(ERROR, diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c index bbd6b77..e5a55e3 100644 --- a/src/backend/rewrite/rewriteHandler.c +++ b/src/backend/rewrite/rewriteHandler.c @@ -811,7 +811,8 @@ rewriteTargetListIU(List *targetList, COERCE_IMPLICIT_CAST, -1, false, - false); + false, + NULL); } } @@ -1066,7 +1067,8 @@ build_column_default(Relation rel, int attrno) atttype, atttypmod, COERCION_ASSIGNMENT, COERCE_IMPLICIT_CAST, - -1); + -1, + NameStr(att_tup->attname)); if (expr == NULL) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), @@ -1176,7 +1178,8 @@ rewriteValuesRTE(RangeTblEntry *rte, Relation target_relation, List *attrnos) COERCE_IMPLICIT_CAST, -1, false, - false); + false, + NULL); } newList = lappend(newList, new_expr); } diff --git a/src/backend/rewrite/rewriteManip.c b/src/backend/rewrite/rewriteManip.c index 1da90ff..eea17dd 100644 --- a/src/backend/rewrite/rewriteManip.c +++ b/src/backend/rewrite/rewriteManip.c @@ -1406,7 +1406,8 @@ ReplaceVarsFromTargetList_callback(Var *var, COERCE_IMPLICIT_CAST, -1, false, - false); + false, + NULL); } elog(ERROR, "could not find replacement targetlist entry for attno %d", var->varattno); diff --git a/src/backend/utils/adt/varchar.c b/src/backend/utils/adt/varchar.c index df9a2d7..1a9eec4 100644 --- a/src/backend/utils/adt/varchar.c +++ b/src/backend/utils/adt/varchar.c @@ -267,6 +267,7 @@ bpchar(PG_FUNCTION_ARGS) BpChar *source = PG_GETARG_BPCHAR_PP(0); int32 maxlen = PG_GETARG_INT32(1); bool isExplicit = PG_GETARG_BOOL(2); + char *colname = PG_GETARG_CSTRING(3); BpChar *result; int32 len; char *r; @@ -303,7 +304,8 @@ bpchar(PG_FUNCTION_ARGS) if (s[i] != ' ') ereport(ERROR, (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION), - errmsg("value too long for type character(%d)", + errmsg("value too long for %s of type character(%d)", + colname, maxlen))); } @@ -594,6 +596,7 @@ varchar(PG_FUNCTION_ARGS) VarChar *source = PG_GETARG_VARCHAR_PP(0); int32 typmod = PG_GETARG_INT32(1); bool isExplicit = PG_GETARG_BOOL(2); + char *colname = PG_GETARG_CSTRING(3); int32 len, maxlen; size_t maxmblen; @@ -619,7 +622,8 @@ varchar(PG_FUNCTION_ARGS) if (s_data[i] != ' ') ereport(ERROR, (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION), - errmsg("value too long for type character varying(%d)", + errmsg("value too long for %s of type character varying(%d)", + colname ? colname : "(unknown column)", maxlen))); } diff --git a/src/include/parser/parse_coerce.h b/src/include/parser/parse_coerce.h index ec0ee14..cb131ce 100644 --- a/src/include/parser/parse_coerce.h +++ b/src/include/parser/parse_coerce.h @@ -40,17 +40,18 @@ extern Node *coerce_to_target_type(ParseState *pstate, Oid targettype, int32 targettypmod, CoercionContext ccontext, CoercionForm cformat, - int location); + int location, + char *colname); extern bool can_coerce_type(int nargs, Oid *input_typeids, Oid *target_typeids, CoercionContext ccontext); extern Node *coerce_type(ParseState *pstate, Node *node, Oid inputTypeId, Oid targetTypeId, int32 targetTypeMod, - CoercionContext ccontext, CoercionForm cformat, int location); + CoercionContext ccontext, CoercionForm cformat, int location, char *colname); extern Node *coerce_to_domain(Node *arg, Oid baseTypeId, int32 baseTypeMod, Oid typeId, CoercionForm cformat, int location, bool hideInputCoercion, - bool lengthCoercionDone); + bool lengthCoercionDone, char *colname); extern Node *coerce_to_boolean(ParseState *pstate, Node *node, const char *constructName); diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c index aac7cda..9677887 100644 --- a/src/pl/plpgsql/src/pl_exec.c +++ b/src/pl/plpgsql/src/pl_exec.c @@ -6022,7 +6022,8 @@ get_cast_expression(PLpgSQL_execstate *estate, dsttype, dsttypmod, COERCION_ASSIGNMENT, COERCE_IMPLICIT_CAST, - -1); + -1, + NULL); /* * If there's no cast path according to the parser, fall back to using an @@ -6046,7 +6047,8 @@ get_cast_expression(PLpgSQL_execstate *estate, dsttype, dsttypmod, COERCION_ASSIGNMENT, COERCE_IMPLICIT_CAST, - -1); + -1, + NULL); } /* Note: we don't bother labeling the expression tree with collation */