|
17 | 17 | * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
|
18 | 18 | * Portions Copyright (c) 1994, Regents of the University of California
|
19 | 19 | *
|
20 |
| - * $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.403 2010/08/27 20:30:08 petere Exp $ |
| 20 | + * $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.404 2010/09/18 18:37:01 tgl Exp $ |
21 | 21 | *
|
22 | 22 | *-------------------------------------------------------------------------
|
23 | 23 | */
|
@@ -47,6 +47,7 @@ static Query *transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt);
|
47 | 47 | static Query *transformInsertStmt(ParseState *pstate, InsertStmt *stmt);
|
48 | 48 | static List *transformInsertRow(ParseState *pstate, List *exprlist,
|
49 | 49 | List *stmtcols, List *icolumns, List *attrnos);
|
| 50 | +static int count_rowexpr_columns(ParseState *pstate, Node *expr); |
50 | 51 | static Query *transformSelectStmt(ParseState *pstate, SelectStmt *stmt);
|
51 | 52 | static Query *transformValuesClause(ParseState *pstate, SelectStmt *stmt);
|
52 | 53 | static Query *transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt);
|
@@ -726,12 +727,27 @@ transformInsertRow(ParseState *pstate, List *exprlist,
|
726 | 727 | list_length(icolumns))))));
|
727 | 728 | if (stmtcols != NIL &&
|
728 | 729 | list_length(exprlist) < list_length(icolumns))
|
| 730 | + { |
| 731 | + /* |
| 732 | + * We can get here for cases like INSERT ... SELECT (a,b,c) FROM ... |
| 733 | + * where the user accidentally created a RowExpr instead of separate |
| 734 | + * columns. Add a suitable hint if that seems to be the problem, |
| 735 | + * because the main error message is quite misleading for this case. |
| 736 | + * (If there's no stmtcols, you'll get something about data type |
| 737 | + * mismatch, which is less misleading so we don't worry about giving |
| 738 | + * a hint in that case.) |
| 739 | + */ |
729 | 740 | ereport(ERROR,
|
730 | 741 | (errcode(ERRCODE_SYNTAX_ERROR),
|
731 | 742 | errmsg("INSERT has more target columns than expressions"),
|
| 743 | + ((list_length(exprlist) == 1 && |
| 744 | + count_rowexpr_columns(pstate, linitial(exprlist)) == |
| 745 | + list_length(icolumns)) ? |
| 746 | + errhint("The insertion source is a row expression containing the same number of columns expected by the INSERT. Did you accidentally use extra parentheses?") : 0), |
732 | 747 | parser_errposition(pstate,
|
733 | 748 | exprLocation(list_nth(icolumns,
|
734 | 749 | list_length(exprlist))))));
|
| 750 | + } |
735 | 751 |
|
736 | 752 | /*
|
737 | 753 | * Prepare columns for assignment to target table.
|
@@ -762,6 +778,49 @@ transformInsertRow(ParseState *pstate, List *exprlist,
|
762 | 778 | return result;
|
763 | 779 | }
|
764 | 780 |
|
| 781 | +/* |
| 782 | + * count_rowexpr_columns - |
| 783 | + * get number of columns contained in a ROW() expression; |
| 784 | + * return -1 if expression isn't a RowExpr or a Var referencing one. |
| 785 | + * |
| 786 | + * This is currently used only for hint purposes, so we aren't terribly |
| 787 | + * tense about recognizing all possible cases. The Var case is interesting |
| 788 | + * because that's what we'll get in the INSERT ... SELECT (...) case. |
| 789 | + */ |
| 790 | +static int |
| 791 | +count_rowexpr_columns(ParseState *pstate, Node *expr) |
| 792 | +{ |
| 793 | + if (expr == NULL) |
| 794 | + return -1; |
| 795 | + if (IsA(expr, RowExpr)) |
| 796 | + return list_length(((RowExpr *) expr)->args); |
| 797 | + if (IsA(expr, Var)) |
| 798 | + { |
| 799 | + Var *var = (Var *) expr; |
| 800 | + AttrNumber attnum = var->varattno; |
| 801 | + |
| 802 | + if (attnum > 0 && var->vartype == RECORDOID) |
| 803 | + { |
| 804 | + RangeTblEntry *rte; |
| 805 | + |
| 806 | + rte = GetRTEByRangeTablePosn(pstate, var->varno, var->varlevelsup); |
| 807 | + if (rte->rtekind == RTE_SUBQUERY) |
| 808 | + { |
| 809 | + /* Subselect-in-FROM: examine sub-select's output expr */ |
| 810 | + TargetEntry *ste = get_tle_by_resno(rte->subquery->targetList, |
| 811 | + attnum); |
| 812 | + |
| 813 | + if (ste == NULL || ste->resjunk) |
| 814 | + return -1; |
| 815 | + expr = (Node *) ste->expr; |
| 816 | + if (IsA(expr, RowExpr)) |
| 817 | + return list_length(((RowExpr *) expr)->args); |
| 818 | + } |
| 819 | + } |
| 820 | + } |
| 821 | + return -1; |
| 822 | +} |
| 823 | + |
765 | 824 |
|
766 | 825 | /*
|
767 | 826 | * transformSelectStmt -
|
|
0 commit comments