Changeset: fa18c6cd7a97 for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=fa18c6cd7a97
Added Files:
        sql/test/miscellaneous/Tests/values.sql
        sql/test/miscellaneous/Tests/values.stable.err
        sql/test/miscellaneous/Tests/values.stable.out
Modified Files:
        sql/server/rel_select.c
        sql/server/rel_semantic.c
        sql/server/sql_parser.y
        
sql/test/BugTracker-2017/Tests/sqlitelogictest-cast-decimal.Bug-6445.stable.out
        
sql/test/BugTracker-2018/Tests/sqlitelogictest-cast-null-add.Bug-6630.stable.out
        sql/test/miscellaneous/Tests/All
Branch: default
Log Message:

Implemented values (...) as a SQL query. This was a SQL standard feature 
missing from MonetDB.

Instead of writing
SELECT a,b UNION SELECT c,d UNION SELECT e,f
we can just write
VALUES (a,b), (c,d), (e,f)


diffs (truncated from 440 to 300 lines):

diff --git a/sql/server/rel_select.c b/sql/server/rel_select.c
--- a/sql/server/rel_select.c
+++ b/sql/server/rel_select.c
@@ -717,17 +717,17 @@ rel_values(sql_query *query, symbol *tab
        dnode *o;
        node *m;
        list *exps = sa_list(sql->sa);
-
        exp_kind ek = {type_value, card_value, TRUE};
-       if (!rowlist->h)
-               r = rel_project(sql->sa, NULL, NULL);
-
-       /* last element in the list is the table_name */
-       for (o = rowlist->h; o->next; o = o->next) {
+
+       for (o = rowlist->h; o; o = o->next) {
                dlist *values = o->data.lval;
 
-               if (r && list_length(r->exps) != dlist_length(values)) {
-                       return sql_error(sql, 02, SQLSTATE(42000) "VALUES: 
number of values doesn't match");
+               /* When performing sub-queries, the relation name appears under 
a SQL_NAME symbol at the end of the list */
+               if (o->type == type_symbol && o->data.sym->token == SQL_NAME)
+                       break;
+
+               if (!list_empty(exps) && list_length(exps) != 
dlist_length(values)) {
+                       return sql_error(sql, 02, SQLSTATE(42000) "VALUES: 
number of columns doesn't match between rows");
                } else {
                        dnode *n;
 
@@ -2606,6 +2606,8 @@ rel_logical_value_exp(sql_query *query, 
                        return rel_lastexp(sql, *rel);
                return NULL;
        }
+       case SQL_DEFAULT:
+               return sql_error(sql, 02, SQLSTATE(42000) "DEFAULT keyword not 
allowed outside insert and update statements");
        default: {
                sql_exp *re, *le = rel_value_exp(query, rel, sc, f, ek);
                sql_subtype bt;
@@ -3272,6 +3274,8 @@ rel_logical_exp(sql_query *query, sql_re
        case SQL_EXCEPT:
        case SQL_INTERSECT:
                return rel_setquery(query, rel, sc);
+       case SQL_DEFAULT:
+               return sql_error(sql, 02, SQLSTATE(42000) "DEFAULT keyword not 
allowed outside insert and update statements");
        default: {
                sql_exp *re, *le = rel_value_exp(query, &rel, sc, f, ek);
 
@@ -5814,6 +5818,8 @@ rel_value_exp2(sql_query *query, sql_rel
        case SQL_COALESCE:
        case SQL_NULLIF:
                return rel_case_exp(query, rel, se, f);
+       case SQL_DEFAULT:
+               return sql_error(sql, 02, SQLSTATE(42000) "DEFAULT keyword not 
allowed outside insert and update statements");
        case SQL_XMLELEMENT:
        case SQL_XMLFOREST:
        case SQL_XMLCOMMENT:
@@ -6422,8 +6428,6 @@ rel_setquery(sql_query *query, sql_rel *
        return res;
 }
 
-
-
 static sql_rel *
 rel_joinquery_(sql_query *query, sql_rel *rel, symbol *tab1, int natural, jt 
jointype, symbol *tab2, symbol *js)
 {
@@ -6682,6 +6686,10 @@ rel_selects(sql_query *query, symbol *s)
                ret = rel_with_query(query, s);
                sql->type = Q_TABLE;
                break;
+       case SQL_VALUES:
+               ret = rel_values(query, s);
+               sql->type = Q_TABLE;
+               break;
        case SQL_SELECT: {
                exp_kind ek = {type_value, card_relation, TRUE};
                SelectNode *sn = (SelectNode *) s;
diff --git a/sql/server/rel_semantic.c b/sql/server/rel_semantic.c
--- a/sql/server/rel_semantic.c
+++ b/sql/server/rel_semantic.c
@@ -234,6 +234,7 @@ rel_semantic(sql_query *query, symbol *s
        case SQL_UNION:
        case SQL_EXCEPT:
        case SQL_INTERSECT:
+       case SQL_VALUES:
                return rel_selects(query, s);
 
        default:
diff --git a/sql/server/sql_parser.y b/sql/server/sql_parser.y
--- a/sql/server/sql_parser.y
+++ b/sql/server/sql_parser.y
@@ -3223,8 +3223,6 @@ values_or_query_spec:
                { $$ = _symbol_create_list( SQL_VALUES, L()); }
  |   DEFAULT VALUES
                { $$ = _symbol_create_list( SQL_VALUES, L()); }
- |   VALUES row_commalist
-               { $$ = _symbol_create_list( SQL_VALUES, $2); }
  |  query_expression
  ;
 
@@ -3437,11 +3435,9 @@ with_query_expression:
  | merge_stmt
  ;
 
-
 sql:
-    select_statement_single_row
-|
-    select_no_parens_orderby
+   select_statement_single_row
+ | select_no_parens_orderby
  ;
 
 simple_select:
@@ -3536,6 +3532,7 @@ select_no_parens:
          append_list(l, $4);
          append_symbol(l, $5);
          $$ = _symbol_create_list( SQL_INTERSECT, l); }
+ |  VALUES row_commalist     { $$ = _symbol_create_list( SQL_VALUES, $2); }
  |  '(' select_no_parens ')' { $$ = $2; }
  |   simple_select
  ;
@@ -4018,21 +4015,14 @@ filter_exp:
                  $$ = _symbol_create_list(SQL_FILTER, l ); }
  ;
 
-
 subquery_with_orderby:
     '(' select_no_parens_orderby ')'   { $$ = $2; }
- |  '(' VALUES row_commalist ')'       
-                               { $$ = _symbol_create_list( SQL_VALUES, $3); }
- |  '(' with_query ')' 
-                               { $$ = $2; }
+ |  '(' with_query ')'                 { $$ = $2; }
  ;
 
 subquery:
     '(' select_no_parens ')'   { $$ = $2; }
- |  '(' VALUES row_commalist ')'       
-                               { $$ = _symbol_create_list( SQL_VALUES, $3); }
- |  '(' with_query ')' 
-                               { $$ = $2; }
+ |  '(' with_query ')'         { $$ = $2; }
  ;
 
        /* simple_scalar expressions */
diff --git 
a/sql/test/BugTracker-2017/Tests/sqlitelogictest-cast-decimal.Bug-6445.stable.out
 
b/sql/test/BugTracker-2017/Tests/sqlitelogictest-cast-decimal.Bug-6445.stable.out
--- 
a/sql/test/BugTracker-2017/Tests/sqlitelogictest-cast-decimal.Bug-6445.stable.out
+++ 
b/sql/test/BugTracker-2017/Tests/sqlitelogictest-cast-decimal.Bug-6445.stable.out
@@ -30,7 +30,7 @@ stdout of test 'sqlitelogictest-cast-dec
 % real # type
 % 15 # length
 #SELECT col0 + - - CAST( NULL AS DECIMAL ) - + col0 + + col1 FROM tab1 cor0 
WHERE ( NULL ) IS NOT NULL;
-% .L3 # table_name
+% sys.L3 # table_name
 % L3 # name
 % decimal # type
 % 20 # length
diff --git 
a/sql/test/BugTracker-2018/Tests/sqlitelogictest-cast-null-add.Bug-6630.stable.out
 
b/sql/test/BugTracker-2018/Tests/sqlitelogictest-cast-null-add.Bug-6630.stable.out
--- 
a/sql/test/BugTracker-2018/Tests/sqlitelogictest-cast-null-add.Bug-6630.stable.out
+++ 
b/sql/test/BugTracker-2018/Tests/sqlitelogictest-cast-null-add.Bug-6630.stable.out
@@ -73,7 +73,7 @@ stdout of test 'sqlitelogictest-cast-nul
 [ NULL ]
 #SELECT ALL CAST ( col1 / - - ( + CAST ( NULL AS INTEGER ) ) AS BIGINT ) col0,
 #           CAST ( 39 + + + CAST ( NULL AS INTEGER ) + + - 10 + col1 / - col0 
AS BIGINT ) AS col1 FROM tab2;
-% .L4, .L10 # table_name
+% sys.L4,      .L10 # table_name
 % col0,        col1 # name
 % bigint,      bigint # type
 % 1,   1 # length
diff --git a/sql/test/miscellaneous/Tests/All b/sql/test/miscellaneous/Tests/All
--- a/sql/test/miscellaneous/Tests/All
+++ b/sql/test/miscellaneous/Tests/All
@@ -5,4 +5,5 @@ trace_test
 simple_selects
 update_delete_aliases
 groupby_expressions
+values
 with_update_stmts
diff --git a/sql/test/miscellaneous/Tests/values.sql 
b/sql/test/miscellaneous/Tests/values.sql
new file mode 100644
--- /dev/null
+++ b/sql/test/miscellaneous/Tests/values.sql
@@ -0,0 +1,32 @@
+values (1);
+values (NULL);
+values (1,2,3);
+values (1,2,3), (4,NULL,6), (7,8,NULL);
+values (); --error
+values (default); --error
+values (1,2), (1), (3,3); --error
+values (1), ('ok');
+values (1) union values (3);
+values (1,1) union values (1,1);
+values (1,2,3) union all values (1,2,3);
+values (3), (2) intersect values (3);
+values (1,2,3), (4,5,6) except select 1,2,4;
+values (1,2,3), (4,5,6) except select 1,2,3;
+select 'a', 'c' union select 'b', 'c' except values ('a', 'c'), ('b', 'c');
+select 'a', 'c' union select 'b', 'c' except values ('a', 'c'), ('b', 'd');
+with t1(a,b) as (values (1,2), (3,5)) select t1.b from t1 where a > 1;
+with t1(a,b) as (values (1,1), (2,2)),
+     t2(a,b) as (values (2,4), (3,3))
+     select * from t1 inner join t2 on t1.a = t2.a;
+with t1(a,b) as (values (1,1), (2,2)),
+     t2(a,b) as (values (2,4), (3,3,5))
+     select * from t1 inner join t2 on t1.a = t2.a; --error
+with t1(a,b) as (select 1) select * from t1; --error
+with t1 as (select 1) values (2);
+with t1 as (select 1) values (3,4,5,6,7,'ok'), (6,8,1,2,'still','ok');
+
+create function foo() returns table (aa int, bb int) begin return table(values 
(1,2), (3)); end; --error
+create function foo() returns table (aa int, bb int) begin return table(values 
(1,2)); end;
+select aa, bb + 1 from foo();
+select cc from foo() as bar(cc, dd);
+drop function foo;
diff --git a/sql/test/miscellaneous/Tests/values.stable.err 
b/sql/test/miscellaneous/Tests/values.stable.err
new file mode 100644
--- /dev/null
+++ b/sql/test/miscellaneous/Tests/values.stable.err
@@ -0,0 +1,62 @@
+stderr of test 'values` in directory 'sql/test/miscellaneous` itself:
+
+
+# 16:16:10 >  
+# 16:16:10 >  "mserver5" "--debug=10" "--set" "gdk_nr_threads=0" "--set" 
"mapi_open=true" "--set" "mapi_port=33718" "--set" 
"mapi_usock=/var/tmp/mtest-17929/.s.monetdb.33718" "--set" "monet_prompt=" 
"--forcemito" 
"--dbpath=/home/ferreira/repositories/MonetDB-default/BUILD/var/MonetDB/mTests_sql_test_miscellaneous"
 "--set" "monet_daemon=yes" "--set" "embedded_c=true"
+# 16:16:10 >  
+
+# builtin opt  gdk_dbpath = 
/home/ferreira/repositories/MonetDB-default/BUILD/var/monetdb5/dbfarm/demo
+# builtin opt  monet_prompt = >
+# builtin opt  monet_daemon = no
+# builtin opt  mapi_port = 50000
+# builtin opt  mapi_open = false
+# builtin opt  mapi_ipv6 = false
+# builtin opt  mapi_autosense = false
+# builtin opt  sql_optimizer = default_pipe
+# builtin opt  sql_debug = 0
+# cmdline opt  gdk_nr_threads = 0
+# cmdline opt  mapi_open = true
+# cmdline opt  mapi_port = 33718
+# cmdline opt  mapi_usock = /var/tmp/mtest-17929/.s.monetdb.33718
+# cmdline opt  monet_prompt = 
+# cmdline opt  gdk_dbpath = 
/home/ferreira/repositories/MonetDB-default/BUILD/var/MonetDB/mTests_sql_test_miscellaneous
+# cmdline opt  monet_daemon = yes
+# cmdline opt  embedded_c = true
+#client2:!ERROR:ParseException:SQLparser:42000!syntax error, unexpected ')' 
in: "values ()"
+#client2:!ERROR:ParseException:SQLparser:42000!VALUES: number of columns 
doesn't match between rows
+
+# 16:16:11 >  
+# 16:16:11 >  "mclient" "-lsql" "-ftest" "-tnone" "-Eutf-8" "-i" "-e" 
"--host=/var/tmp/mtest-17929" "--port=33718"
+# 16:16:11 >  
+
+MAPI  = (monetdb) /var/tmp/mtest-17929/.s.monetdb.33718
+QUERY = values (); --error
+ERROR = !syntax error, unexpected ')' in: "values ()"
+CODE  = 42000
+MAPI  = (monetdb) /var/tmp/mtest-2671/.s.monetdb.33813
+QUERY = values (default); --error
+ERROR = !DEFAULT keyword not allowed outside insert and update statements
+CODE  = 42000
+MAPI  = (monetdb) /var/tmp/mtest-2671/.s.monetdb.33813
+QUERY = values (1,2), (1), (3,3); --error
+ERROR = !VALUES: number of columns doesn't match between rows
+CODE  = 42000
+MAPI  = (monetdb) /var/tmp/mtest-20225/.s.monetdb.30800
+QUERY = with t1(a,b) as (values (1,1), (2,2)),
+             t2(a,b) as (values (2,4), (3,3,5))
+             select * from t1 inner join t2 on t1.a = t2.a; --error
+ERROR = !VALUES: number of columns doesn't match between rows
+CODE  = 42000
+MAPI  = (monetdb) /var/tmp/mtest-20225/.s.monetdb.30800
+QUERY = with t1(a,b) as (select 1) select * from t1; --error
+ERROR = !WITH CLAUSE: number of columns does not match
+CODE  = 21S02
+MAPI  = (monetdb) /var/tmp/mtest-20225/.s.monetdb.30800
+QUERY = create function foo() returns table (aa int, bb int) begin return 
table(values (1,2), (3)); end; --error
+ERROR = !VALUES: number of columns doesn't match between rows
+CODE  = 42000
+
+# 16:16:11 >  
+# 16:16:11 >  "Done."
+# 16:16:11 >  
+
diff --git a/sql/test/miscellaneous/Tests/values.stable.out 
b/sql/test/miscellaneous/Tests/values.stable.out
new file mode 100644
--- /dev/null
+++ b/sql/test/miscellaneous/Tests/values.stable.out
@@ -0,0 +1,153 @@
+stdout of test 'values` in directory 'sql/test/miscellaneous` itself:
+
+
+# 16:16:10 >  
+# 16:16:10 >  "mserver5" "--debug=10" "--set" "gdk_nr_threads=0" "--set" 
"mapi_open=true" "--set" "mapi_port=33718" "--set" 
"mapi_usock=/var/tmp/mtest-17929/.s.monetdb.33718" "--set" "monet_prompt=" 
"--forcemito" 
"--dbpath=/home/ferreira/repositories/MonetDB-default/BUILD/var/MonetDB/mTests_sql_test_miscellaneous"
 "--set" "monet_daemon=yes" "--set" "embedded_c=true"
+# 16:16:10 >  
+
+# MonetDB 5 server v11.34.0 (hg id: 46ba7db7f1bd)
+# This is an unreleased version
+# Serving database 'mTests_sql_test_miscellaneous', using 8 threads
+# Compiled for x86_64-pc-linux-gnu/64bit with 128bit integers
+# Found 15.527 GiB available main-memory.
+# Copyright (c) 1993 - July 2008 CWI.
_______________________________________________
checkin-list mailing list
checkin-list@monetdb.org
https://www.monetdb.org/mailman/listinfo/checkin-list

Reply via email to