Hello!
I have created a patch to allow additional commas between columns, and
at the end of the SELECT clause.
Motivation:
Commas of this type are allowed in many programming languages, in some
it is even recommended to use them at the ends of lists or objects. A
new generation of programmers expects a more forgiving language just as
our generation enjoyed LIMIT and the ability to write `select` in lowercase.
Accepted:
SELECT 1,;
SELECT 1,,,,,;
SELECT *, from information_schema.sql_features;
(...) RETURNING a,,b,c,;
Not accepted:
SELECT ,;
SELECT ,1;
SELECT ,,,;
Advantages:
- simplifies the creation and debugging of queries by reducing the most
common syntax error,
- eliminates the need to use the popular `1::int as dummy` at the end of
a SELECT list,
- simplifies query generators,
- the query is still deterministic,
Disadvantages:
- counting of returned columns can be difficult,
- syntax checkers will still report errors,
- probably not SQL standard compliant,
- functionality can be controversial,
I attach the patch along with the tests.
What do you think?
Your opinions are very much welcome!
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index e8b619926e..8bf0a2690e 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -17174,6 +17174,7 @@ opt_target_list: target_list
{ $$ = $1; }
target_list:
target_el
{ $$ = list_make1($1); }
| target_list ',' target_el
{ $$ = lappend($1, $3); }
+ | target_list ','
/* Handling trailing comma */
;
target_el: a_expr AS ColLabel
diff --git a/src/test/regress/expected/returning.out
b/src/test/regress/expected/returning.out
index cb51bb8687..8604e50e18 100644
--- a/src/test/regress/expected/returning.out
+++ b/src/test/regress/expected/returning.out
@@ -238,7 +238,7 @@ CREATE OR REPLACE RULE voo_u AS ON UPDATE TO voo DO INSTEAD
UPDATE foo SET f1 = new.f1, f2 = new.f2 WHERE f1 = old.f1
RETURNING f1, f2;
update voo set f1 = f1 + 1 where f2 = 'zoo2';
-update voo set f1 = f1 + 1 where f2 = 'zoo2' RETURNING *, f1*2;
+update voo set f1 = f1 + 1 where f2 = 'zoo2' RETURNING *, f1*2,;
f1 | f2 | ?column?
----+------+----------
16 | zoo2 | 32
@@ -264,7 +264,7 @@ SELECT * FROM voo;
CREATE OR REPLACE RULE voo_d AS ON DELETE TO voo DO INSTEAD
DELETE FROM foo WHERE f1 = old.f1
- RETURNING f1, f2;
+ RETURNING f1, , , , f2;
DELETE FROM foo WHERE f1 = 13;
DELETE FROM foo WHERE f2 = 'zit' RETURNING *;
f1 | f2 | f3 | f4
diff --git a/src/test/regress/expected/select.out
b/src/test/regress/expected/select.out
index 33a6dceb0e..e4b9e916da 100644
--- a/src/test/regress/expected/select.out
+++ b/src/test/regress/expected/select.out
@@ -968,3 +968,50 @@ explain (costs off) select * from list_parted_tbl;
(2 rows)
drop table list_parted_tbl;
+-- Handling trailing comma
+SELECT *, FROM onek
+ WHERE onek.unique1 < 10
+ ORDER BY onek.unique1;
+ unique1 | unique2 | two | four | ten | twenty | hundred | thousand |
twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4
+---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+---------
+ 0 | 998 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 1 | AAAAAA | KMBAAA | OOOOxx
+ 1 | 214 | 1 | 1 | 1 | 1 | 1 | 1 |
1 | 1 | 1 | 2 | 3 | BAAAAA | GIAAAA | OOOOxx
+ 2 | 326 | 0 | 2 | 2 | 2 | 2 | 2 |
2 | 2 | 2 | 4 | 5 | CAAAAA | OMAAAA | OOOOxx
+ 3 | 431 | 1 | 3 | 3 | 3 | 3 | 3 |
3 | 3 | 3 | 6 | 7 | DAAAAA | PQAAAA | VVVVxx
+ 4 | 833 | 0 | 0 | 4 | 4 | 4 | 4 |
4 | 4 | 4 | 8 | 9 | EAAAAA | BGBAAA | HHHHxx
+ 5 | 541 | 1 | 1 | 5 | 5 | 5 | 5 |
5 | 5 | 5 | 10 | 11 | FAAAAA | VUAAAA | HHHHxx
+ 6 | 978 | 0 | 2 | 6 | 6 | 6 | 6 |
6 | 6 | 6 | 12 | 13 | GAAAAA | QLBAAA | OOOOxx
+ 7 | 647 | 1 | 3 | 7 | 7 | 7 | 7 |
7 | 7 | 7 | 14 | 15 | HAAAAA | XYAAAA | VVVVxx
+ 8 | 653 | 0 | 0 | 8 | 8 | 8 | 8 |
8 | 8 | 8 | 16 | 17 | IAAAAA | DZAAAA | HHHHxx
+ 9 | 49 | 1 | 1 | 9 | 9 | 9 | 9 |
9 | 9 | 9 | 18 | 19 | JAAAAA | XBAAAA | HHHHxx
+(10 rows)
+
+SELECT 1,,2,,,3 as dummy,;
+ ?column? | ?column? | dummy
+----------+----------+-------
+ 1 | 2 | 3
+(1 row)
+
+SELECT count(*),;
+ count
+-------
+ 1
+(1 row)
+
+SELECT count(*), FROM onek;
+ count
+-------
+ 1000
+(1 row)
+
+SELECT v.k as x, FROM (VALUES(1)) v(k);
+ x
+---
+ 1
+(1 row)
+
+-- Error is expected
+SELECT ,;
+ERROR: syntax error at or near ","
+LINE 1: SELECT ,;
+ ^
diff --git a/src/test/regress/sql/returning.sql
b/src/test/regress/sql/returning.sql
index a460f82fb7..a3cb0586af 100644
--- a/src/test/regress/sql/returning.sql
+++ b/src/test/regress/sql/returning.sql
@@ -117,14 +117,14 @@ CREATE OR REPLACE RULE voo_u AS ON UPDATE TO voo DO
INSTEAD
RETURNING f1, f2;
update voo set f1 = f1 + 1 where f2 = 'zoo2';
-update voo set f1 = f1 + 1 where f2 = 'zoo2' RETURNING *, f1*2;
+update voo set f1 = f1 + 1 where f2 = 'zoo2' RETURNING *, f1*2,;
SELECT * FROM foo;
SELECT * FROM voo;
CREATE OR REPLACE RULE voo_d AS ON DELETE TO voo DO INSTEAD
DELETE FROM foo WHERE f1 = old.f1
- RETURNING f1, f2;
+ RETURNING f1, , , , f2;
DELETE FROM foo WHERE f1 = 13;
DELETE FROM foo WHERE f2 = 'zit' RETURNING *;
diff --git a/src/test/regress/sql/select.sql b/src/test/regress/sql/select.sql
index 019f1e7673..e98794c135 100644
--- a/src/test/regress/sql/select.sql
+++ b/src/test/regress/sql/select.sql
@@ -262,3 +262,20 @@ create table list_parted_tbl1 partition of list_parted_tbl
for values in (1) partition by list(b);
explain (costs off) select * from list_parted_tbl;
drop table list_parted_tbl;
+
+
+-- Handling trailing comma
+SELECT *, FROM onek
+ WHERE onek.unique1 < 10
+ ORDER BY onek.unique1;
+
+SELECT 1,,2,,,3 as dummy,;
+
+SELECT count(*),;
+
+SELECT count(*), FROM onek;
+
+SELECT v.k as x, FROM (VALUES(1)) v(k);
+
+-- Error is expected
+SELECT ,;