Re: ruleutils vs. empty targetlists
От | Tom Lane |
---|---|
Тема | Re: ruleutils vs. empty targetlists |
Дата | |
Msg-id | 21007.1386897293@sss.pgh.pa.us обсуждение исходный текст |
Ответ на | Re: ruleutils vs. empty targetlists (Alvaro Herrera <alvherre@2ndquadrant.com>) |
Ответы |
Re: ruleutils vs. empty targetlists
|
Список | pgsql-hackers |
Alvaro Herrera <alvherre@2ndquadrant.com> writes: > Tom Lane escribi�: >> What I'm thinking about this today is that really the *right* solution >> is to allow syntactically-empty SELECT lists; once we've bought into the >> notion of zero-column tables, the notion that you can't have an empty >> select list is just fundamentally at odds with that. And since you can >> already have semantically-empty SELECT lists, this should in theory not >> create much risk of new bugs. If we did that, the existing ruleutils >> code is just fine, as are any existing dump files containing this sort >> of query. > Wow, as strange-sounding as that is, you're probably correct. I experimented with this a bit, and found that things seem to pretty much work, although unsurprisingly there are a couple of regression tests that expected to get a syntax error and no longer do. The only thing I've come across that arguably doesn't work is SELECT DISTINCT: regression=# select distinct from pg_database; -- (8 rows) The reason this says "8 rows" is that the produced plan is just a seqscan of pg_database returning no columns. The parser produced a Query with an empty distinctClause, so the planner thinks no unique-ification is required, so it doesn't produce any sort/uniq or hashagg node. This seems a bit bogus to me; mathematically, it seems like what this ought to mean is that all rows are equivalent and so you get just one empty row out. However, I don't see any practical use-case for that behavior, so I'm disinclined to spend time on inventing a solution --- and any solution would probably require a change in Query representation, making it not back-patchable anyway. Instead I suggest we add an error check in parse analysis that throws an error for DISTINCT with no columns. If anyone is ever motivated to make this case do something sane, they can remove that check and fix up whatever needs fixing up. The attached first-draft patch doesn't yet have such a prohibition, though. Another point is that there is a second use of target_list in the grammar, which is "RETURNING target_list". I did not change that one into "RETURNING opt_target_list", because if I had, it would have an issue similar to DISTINCT's: RETURNING with no arguments would be represented the same as no RETURNING at all, leading to probably not the behavior the user expected. We've already got that problem if you say "RETURNING zero_column_table.*", making me wonder if a parse-analysis-time error for that case wouldn't be a good thing. Comments? regards, tom lane diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 8fced44..f9d4577 100644 *** a/src/backend/parser/gram.y --- b/src/backend/parser/gram.y *************** static Node *makeRecursiveViewSelect(cha *** 334,340 **** name_list from_clause from_list opt_array_bounds qualified_name_list any_name any_name_list any_operator expr_list attrs ! target_list insert_column_list set_target_list set_clause_list set_clause multiple_set_clause ctext_expr_list ctext_row def_list indirection opt_indirection reloption_list group_clause TriggerFuncArgs select_limit --- 334,340 ---- name_list from_clause from_list opt_array_bounds qualified_name_list any_name any_name_list any_operator expr_list attrs ! target_list opt_target_list insert_column_list set_target_list set_clause_list set_clause multiple_set_clause ctext_expr_list ctext_row def_list indirection opt_indirection reloption_list group_clause TriggerFuncArgs select_limit *************** select_clause: *** 9259,9265 **** * However, this is not checked by the grammar; parse analysis must check it. */ simple_select: ! SELECT opt_distinct target_list into_clause from_clause where_clause group_clause having_clause window_clause { --- 9259,9265 ---- * However, this is not checked by the grammar; parse analysis must check it. */ simple_select: ! SELECT opt_distinct opt_target_list into_clause from_clause where_clause group_clause having_clause window_clause { *************** ctext_row: '(' ctext_expr_list ')' { *** 12215,12220 **** --- 12215,12224 ---- * *****************************************************************************/ + opt_target_list: target_list { $$ = $1; } + | /* EMPTY */ { $$ = NIL; } + ; + target_list: target_el { $$ = list_make1($1); } | target_list ',' target_el { $$ = lappend($1, $3); } diff --git a/src/test/regress/expected/errors.out b/src/test/regress/expected/errors.out index 4061512..b63cb54 100644 *** a/src/test/regress/expected/errors.out --- b/src/test/regress/expected/errors.out *************** select 1; *** 15,35 **** -- -- -- SELECT ! -- missing relation name select; ! ERROR: syntax error at or near ";" ! LINE 1: select; ! ^ -- no such relation select * from nonesuch; ERROR: relation "nonesuch" does not exist LINE 1: select * from nonesuch; ^ - -- missing target list - select from pg_database; - ERROR: syntax error at or near "from" - LINE 1: select from pg_database; - ^ -- bad name in target list select nonesuch from pg_database; ERROR: column "nonesuch" does not exist --- 15,30 ---- -- -- -- SELECT ! -- this used to be a syntax error, but now we allow an empty target list select; ! -- ! (1 row) ! -- no such relation select * from nonesuch; ERROR: relation "nonesuch" does not exist LINE 1: select * from nonesuch; ^ -- bad name in target list select nonesuch from pg_database; ERROR: column "nonesuch" does not exist *************** select * from pg_database where pg_datab *** 45,56 **** ERROR: column "nonesuch" does not exist LINE 1: ...ect * from pg_database where pg_database.datname = nonesuch; ^ ! -- bad select distinct on syntax, distinct attribute missing ! select distinct on (foobar) from pg_database; ! ERROR: syntax error at or near "from" ! LINE 1: select distinct on (foobar) from pg_database; ! ^ ! -- bad select distinct on syntax, distinct attribute not in target list select distinct on (foobar) * from pg_database; ERROR: column "foobar" does not exist LINE 1: select distinct on (foobar) * from pg_database; --- 40,46 ---- ERROR: column "nonesuch" does not exist LINE 1: ...ect * from pg_database where pg_database.datname = nonesuch; ^ ! -- bad attribute name in select distinct on select distinct on (foobar) * from pg_database; ERROR: column "foobar" does not exist LINE 1: select distinct on (foobar) * from pg_database; diff --git a/src/test/regress/sql/errors.sql b/src/test/regress/sql/errors.sql index 2ee707c..80d1b62 100644 *** a/src/test/regress/sql/errors.sql --- b/src/test/regress/sql/errors.sql *************** select 1; *** 16,29 **** -- -- SELECT ! -- missing relation name select; -- no such relation select * from nonesuch; - -- missing target list - select from pg_database; -- bad name in target list select nonesuch from pg_database; -- bad attribute name on lhs of operator --- 16,27 ---- -- -- SELECT ! -- this used to be a syntax error, but now we allow an empty target list select; -- no such relation select * from nonesuch; -- bad name in target list select nonesuch from pg_database; -- bad attribute name on lhs of operator *************** select * from pg_database where nonesuch *** 32,43 **** -- bad attribute name on rhs of operator select * from pg_database where pg_database.datname = nonesuch; ! ! -- bad select distinct on syntax, distinct attribute missing ! select distinct on (foobar) from pg_database; ! ! ! -- bad select distinct on syntax, distinct attribute not in target list select distinct on (foobar) * from pg_database; --- 30,36 ---- -- bad attribute name on rhs of operator select * from pg_database where pg_database.datname = nonesuch; ! -- bad attribute name in select distinct on select distinct on (foobar) * from pg_database;
В списке pgsql-hackers по дате отправления: