Behave correctly if INSERT ... VALUES is decorated with additional clauses.
authorTom Lane <[email protected]>
Sun, 3 Oct 2010 00:02:41 +0000 (20:02 -0400)
committerTom Lane <[email protected]>
Sun, 3 Oct 2010 00:02:41 +0000 (20:02 -0400)
In versions 8.2 and up, the grammar allows attaching ORDER BY, LIMIT,
FOR UPDATE, or WITH to VALUES, and hence to INSERT ... VALUES.  But the
special-case code for VALUES in transformInsertStmt() wasn't expecting any
of those, and just ignored them, leading to unexpected results.  Rather
than complicate the special-case path, just ensure that the presence of any
of those clauses makes us treat the query as if it had a general SELECT.
Per report from Hitoshi Harada.

src/backend/parser/analyze.c

index 244414a61f35efe3bf3c2866a081cf2e92cd3fc8..c1868664ff29c2d5e4da8c20ff48323ea7c05091 100644 (file)
@@ -355,8 +355,17 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
         * We have three cases to deal with: DEFAULT VALUES (selectStmt == NULL),
         * VALUES list, or general SELECT input.  We special-case VALUES, both for
         * efficiency and so we can handle DEFAULT specifications.
+        *
+        * The grammar allows attaching ORDER BY, LIMIT, FOR UPDATE, or WITH to a
+        * VALUES clause.  If we have any of those, treat it as a general SELECT;
+        * so it will work, but you can't use DEFAULT items together with those.
         */
-       isGeneralSelect = (selectStmt && selectStmt->valuesLists == NIL);
+       isGeneralSelect = (selectStmt && (selectStmt->valuesLists == NIL ||
+                                                                         selectStmt->sortClause != NIL ||
+                                                                         selectStmt->limitOffset != NULL ||
+                                                                         selectStmt->limitCount != NULL ||
+                                                                         selectStmt->lockingClause != NIL ||
+                                                                         selectStmt->withClause != NULL));
 
        /*
         * If a non-nil rangetable/namespace was passed in, and we are doing