summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/manual.tex1
-rw-r--r--src/urweb.grm65
-rw-r--r--tests/selclause.ur6
-rw-r--r--tests/selclause.urp4
4 files changed, 67 insertions, 9 deletions
diff --git a/doc/manual.tex b/doc/manual.tex
index e921de74..0c64da4c 100644
--- a/doc/manual.tex
+++ b/doc/manual.tex
@@ -2128,6 +2128,7 @@ $$\begin{array}{rrcll}
&&& p,^+ & \textrm{particular columns} \\
\textrm{Pre-projections} & p &::=& t.f & \textrm{one column from a table} \\
&&& t.\{\{c\}\} & \textrm{a record of columns from a table (of kind $\{\mt{Type}\}$)} \\
+ &&& t.* & \textrm{all columns from a table} \\
&&& E \; [\mt{AS} \; f] & \textrm{expression column} \\
\textrm{Table names} & t &::=& x & \textrm{constant table name (automatically capitalized)} \\
&&& X & \textrm{constant table name} \\
diff --git a/src/urweb.grm b/src/urweb.grm
index bb9ea18b..22616c79 100644
--- a/src/urweb.grm
+++ b/src/urweb.grm
@@ -44,6 +44,7 @@ datatype select_item =
Field of con * con
| Exp of con option * exp
| Fields of con * con
+ | StarFields of con
datatype select =
Star
@@ -65,6 +66,11 @@ fun nameString (c, _) =
| CVar (_, x) => x
| _ => "?"
+datatype tableMode =
+ Unknown
+ | Everything
+ | Selective of con
+
fun amend_select loc (si, (count, tabs, exps)) =
case si of
Field (tx, fx) =>
@@ -73,7 +79,15 @@ fun amend_select loc (si, (count, tabs, exps)) =
val (tabs, found) = ListUtil.foldlMap (fn ((tx', c'), found) =>
if eqTnames (tx, tx') then
- ((tx', (CConcat (c, c'), loc)), true)
+ case c' of
+ Everything =>
+ (ErrorMsg.errorAt loc
+ "Mixing specific-field and '*' selection of fields from same table";
+ ((tx', c'), found))
+ | Unknown =>
+ ((tx', Selective c), true)
+ | Selective c' =>
+ ((tx', Selective (CConcat (c, c'), loc)), true)
else
((tx', c'), found))
false tabs
@@ -89,7 +103,15 @@ fun amend_select loc (si, (count, tabs, exps)) =
let
val (tabs, found) = ListUtil.foldlMap (fn ((tx', c'), found) =>
if eqTnames (tx, tx') then
- ((tx', (CConcat (fs, c'), loc)), true)
+ case c' of
+ Everything =>
+ (ErrorMsg.errorAt loc
+ "Mixing specific-field and '*' selection of fields from same table";
+ ((tx', c'), found))
+ | Selective c' =>
+ ((tx', Selective (CConcat (fs, c'), loc)), true)
+ | Unknown =>
+ ((tx', Selective fs), true)
else
((tx', c'), found))
false tabs
@@ -101,6 +123,17 @@ fun amend_select loc (si, (count, tabs, exps)) =
(count, tabs, exps)
end
+ | StarFields tx =>
+ if List.exists (fn (tx', c') => eqTnames (tx, tx') andalso case c' of
+ Unknown => false
+ | _ => true) tabs then
+ (ErrorMsg.errorAt loc "Selection with '*' from table already mentioned in same SELECT clause";
+ (count, tabs, exps))
+ else if List.all (fn (tx', c') => not (eqTnames (tx, tx'))) tabs then
+ (ErrorMsg.errorAt loc "Select of all fields from unbound table";
+ (count, tabs, exps))
+ else
+ (count, map (fn (tx', c') => (tx', if eqTnames (tx, tx') then Everything else c')) tabs, exps)
| Exp (SOME c, e) => (count, tabs, (c, e) :: exps)
| Exp (NONE, e) => (count+1, tabs, ((CName (Int.toString count), loc), e) :: exps)
@@ -1560,18 +1593,31 @@ query1 : SELECT dopt select FROM tables wopt gopt hopt
[])
| Items sis =>
let
- val tabs = map (fn nm => (nm, (CRecord [], loc))) (#1 tables)
+ val tabs = map (fn nm => (nm, Unknown)) (#1 tables)
val (_, tabs, exps) = foldl (amend_select loc)
(1, tabs, []) sis
- val empties = List.mapPartial (fn (nm, (CRecord [], _)) =>
- SOME nm
- | _ => NONE) tabs
+ val empties = List.mapPartial (fn (nm, c) =>
+ case c of
+ Unknown => SOME nm
+ | Selective (CRecord [], _) => SOME nm
+ | _ => NONE) tabs
in
(empties,
map (fn (nm, c) => (nm,
- (CTuple [c,
- (CWild (KRecord (KType, loc), loc),
- loc)], loc))) tabs,
+ case c of
+ Everything =>
+ (CTuple [(CWild (KRecord (KType, loc), loc), loc),
+ (CRecord [], loc)], loc)
+ | _ =>
+ let
+ val c = case c of
+ Selective c => c
+ | _ => (CRecord [], loc)
+ in
+ (CTuple [c,
+ (CWild (KRecord (KType, loc), loc),
+ loc)], loc)
+ end)) tabs,
exps)
end
@@ -1770,6 +1816,7 @@ seli : tident DOT fident (Field (tident, fident))
| sqlexp (Exp (NONE, sqlexp))
| sqlexp AS fident (Exp (SOME fident, sqlexp))
| tident DOT LBRACE LBRACE cexp RBRACE RBRACE (Fields (tident, cexp))
+ | tident DOT STAR (StarFields tident)
selis : seli ([seli])
| seli COMMA selis (seli :: selis)
diff --git a/tests/selclause.ur b/tests/selclause.ur
new file mode 100644
index 00000000..484c1ebc
--- /dev/null
+++ b/tests/selclause.ur
@@ -0,0 +1,6 @@
+table t : { A : int, B : string, C : float }
+table u : { D : int, E : string, F : float }
+
+val q : transaction (list {T : { A : int, B : string, C : float}, U : { D : int }, X : string }) =
+ queryL (SELECT t.*, u.D, 'hi' AS X
+ FROM t, u)
diff --git a/tests/selclause.urp b/tests/selclause.urp
new file mode 100644
index 00000000..ccd62626
--- /dev/null
+++ b/tests/selclause.urp
@@ -0,0 +1,4 @@
+database dbname=test
+sql selclause.sql
+
+selclause