|
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 | staticQuery*transformInsertStmt(ParseState*pstate,InsertStmt*stmt);
|
48 | 48 | staticList*transformInsertRow(ParseState*pstate,List*exprlist,
|
49 | 49 | List*stmtcols,List*icolumns,List*attrnos);
|
| 50 | +staticintcount_rowexpr_columns(ParseState*pstate,Node*expr); |
50 | 51 | staticQuery*transformSelectStmt(ParseState*pstate,SelectStmt*stmt);
|
51 | 52 | staticQuery*transformValuesClause(ParseState*pstate,SelectStmt*stmt);
|
52 | 53 | staticQuery*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 | returnresult;
|
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 | +staticint |
| 791 | +count_rowexpr_columns(ParseState*pstate,Node*expr) |
| 792 | +{ |
| 793 | +if (expr==NULL) |
| 794 | +return-1; |
| 795 | +if (IsA(expr,RowExpr)) |
| 796 | +returnlist_length(((RowExpr*)expr)->args); |
| 797 | +if (IsA(expr,Var)) |
| 798 | +{ |
| 799 | +Var*var= (Var*)expr; |
| 800 | +AttrNumberattnum=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 | +returnlist_length(((RowExpr*)expr)->args); |
| 818 | +} |
| 819 | +} |
| 820 | +} |
| 821 | +return-1; |
| 822 | +} |
| 823 | + |
765 | 824 |
|
766 | 825 | /*
|
767 | 826 | * transformSelectStmt -
|
|