This commit is contained in:
jackfoxy 2023-03-16 13:49:28 -07:00
parent 6fa1e8bff1
commit 6ed57d85a7
7 changed files with 211 additions and 98 deletions

View File

@ -50,8 +50,6 @@ There are no subqueries.
JOINs and/or CTEs handle all such use cases and emphasize composability.
CTEs can be referenced for certain use cases in predicates.
The result of a UNION set operation is as according to _union_ in set theory (no duplicate rows returned).
Use COMBINE to include duplicates.
Relational division is supported with a DIVIDED BY operator.
Reading and/or updating data on foreign ships is allowed provided the ship's pilot has granted permission.

View File

@ -19,20 +19,14 @@
]
SELECT [ TOP <n> ] [ BOTTOM <n> ] [ DISTINCT ]
{ * | { [<ship-qualifer>]<table-view> | <alias> }.*
| { <qualified-column>
| <constant> }
| <scalar-name>
| <scalar-query>
| <aggregate-function>( { <column> | <scalar-name> } )
} [ [ AS ] <column-alias> ]
| <expression> [ [ AS ] <column-alias> ]
} [ ,...n ]
[ ORDER BY [ { <qualified-column> | <column-alias> | <column-ordinal> }
[ ASC | DESC ]
] [ ,...n ]
]
[ { [ INTO <table> ]
| [ { UNION
| COMBINE
| [ { UNION [ ALL ]
| EXCEPT
| INTERSECT
| DIVIDED BY [ WITH REMAINDER ]
@ -122,8 +116,9 @@ See CH 8 Functions for full documentation on Scalars.
```
<expression> ::=
{ <column>
| <scalar-function>
{ <qualified-column>
| <constant>
| <scalar-name>
| <scalar-query>
| <aggregate-function>( { <column> | <scalar-name> } )
}

View File

@ -37,8 +37,8 @@ Escape single quotes with double backslash thusly `'this is a cor\\'d'`.
# MERGE
```
[ WITH (<query>) AS <alias> [ ,...n ] ]
MERGE [ INTO ] [ <ship-qualifer> ]<target-table-name> [ [ AS ] <alias> ]
[ WITH (<query>) AS <alias> [ ,...n ] ]
USING [ <ship-qualifer> ]<table-source-name> [ [ AS ] <alias> ]
ON <predicate>
[ WHEN MATCHED [ AND <predicate> ]
@ -78,9 +78,9 @@ Tables in the namespace *sys* cannot be truncated.
# UPDATE
```
[WITH (<query>) AS <alias> [ ,...n ] ]
UPDATE [ <ship-qualifer> ]<table-name>
SET { <column-name> = <scalar-expression>
SET { <column-name> = <scalar-expression> } [ ,...n ]
[ WITH (<query>) AS <alias> [ ,...n ] ]
[ WHERE <predicate> ]
```

View File

@ -25,6 +25,7 @@
simple-query:ast
revoke:ast
truncate-table:ast
update:ast
==
+$ command
$%
@ -36,7 +37,6 @@
%create-namespace
%create-table
%create-view
%cte
%delete
%drop-database
%drop-index
@ -48,6 +48,8 @@
%query
%revoke
%truncate-table
%update
%with
==
::
:: helper types
@ -577,8 +579,6 @@
^- (list raw-predicate-component2)
=/ new-list=(list raw-predicate-component2) ~
|-
~| "aggregate-name: {<->-.a>}"
~| "qualified-column: {<->+.a>}"
?: =(a ~) (flop new-list)
?: ?=(parens -.a) $(new-list [i=`parens`-.a t=new-list], a +.a)
?: ?=(ops-and-conjs:ast -.a) $(new-list [i=`ops-and-conjs:ast`-.a t=new-list], a +.a)
@ -1158,25 +1158,28 @@
joined-objects [joined joined-objects]
raw-joined-objects +.raw-joined-objects
==
++ produce-ctes
|= a=*
^- (list cte-query:ast)
=/ ctes=(list cte-query:ast) ~
|-
?~ a (flop ctes)
?: ?&(=(%cte -<.a) =(%as ->+<.a))
%= $
a +.a
ctes [(cte-query:ast %cte ->+>.a (produce-simple-query ->-.a)) ctes]
==
~|('cannot produce ctes from parsed: {<a>}' !!)
++ produce-delete
|= a=*
^- delete:ast
=/ ctes=(list cte-query:ast) ~
?> ?=(qualified-object:ast -.a)
?: =(%where +<.a)
(delete:ast %delete -.a ~ `(produce-predicate (predicate-list +>-.a)))
?: =(%end-command +<.a)
(delete:ast %delete -.a ~ ~)
=/ raw-ctes +<.a
|-
?~ raw-ctes
(delete:ast %delete -.a (flop ctes) `(produce-predicate (predicate-list +>->.a)))
?: ?&(=(%cte -<.raw-ctes) =(%as ->+<.raw-ctes))
%= $
raw-ctes +.raw-ctes
ctes [(cte-query:ast %cte ->+>.raw-ctes (produce-simple-query ->-.raw-ctes)) ctes]
==
~|('cannot produce delete from parsed: {<a>}' !!)
?: =(%where +<.a)
(delete:ast %delete -.a ~ `(produce-predicate (predicate-list +>-.a)))
(delete:ast %delete -.a (produce-ctes +<.a) `(produce-predicate (predicate-list +>->.a)))
++ produce-select
|= a=*
^- select:ast
@ -1436,6 +1439,58 @@
end-or-next-command
==
==
++ parse-merge (jester 'placeholder')
++ update-column-inner ;~ pose
;~(plug sym ;~(pfix whitespace ;~(pfix (jest '=') ;~(pfix whitespace ;~(pose parse-qualified-column parse-value-literal)))))
==
++ produce-column-sets
|= a=*
^- [(list @t) (list datum:ast)]
=/ columns=(list @t) ~
=/ values=(list datum:ast) ~
|-
?: =(a ~)
[columns values]
?: ?&(?=(datum:ast ->.a) ?=(@ -<.a))
%= $
columns [-<.a columns]
values [->.a values]
a +.a
==
~|("cannot parse column setting {<a>}" !!)
++ produce-update
|= a=*
^- update:ast
=/ table=qualified-object:ast ?>(?=(qualified-object:ast -.a) -.a)
=/ columns-values=[(list @t) (list datum:ast)] (produce-column-sets +>-.a)
?~ +>+.a
(update:ast %update table -.columns-values +.columns-values ~ ~)
?: =(%ctes +>+<.a)
(update:ast %update table -.columns-values +.columns-values (produce-ctes +>+>-.a) `(produce-predicate (predicate-list +>+>+.a)))
(update:ast %update table -.columns-values +.columns-values ~ `(produce-predicate (predicate-list +>+.a)))
++ update-column ;~ pose
;~(pfix whitespace ;~(sfix update-column-inner whitespace))
;~(pfix whitespace update-column-inner)
;~(sfix update-column-inner whitespace)
update-column-inner
==
++ parse-update ;~ plug
;~(pfix whitespace parse-qualified-object)
(cold %set ;~(plug whitespace (jester 'set')))
(more com update-column)
;~ pose
;~(plug (cold %ctes ;~(plug whitespace (jester 'with'))) parse-ctes ;~(pfix ;~(plug whitespace (jester 'where')) parse-predicate))
;~(pfix ;~(plug whitespace (jester 'where')) parse-predicate)
(easy ~)
==
==
++ parse-with ;~ plug
parse-ctes
;~ pose
parse-query
;~(plug (jester 'merge') parse-merge)
==
==
++ parse-revoke ;~ plug
:: permission
;~(pfix whitespace ;~(pose (jester 'adminread') (jester 'readonly') (jester 'readwrite') (jester 'all')))
@ -1464,7 +1519,7 @@
(cold %create-table ;~(plug whitespace (jester 'create') whitespace (jester 'table')))
(cold %create-view ;~(plug whitespace (jester 'create') whitespace (jester 'view')))
(cold %create-index ;~(plug whitespace (jester 'create'))) :: must be last of creates
(cold %cte ;~(plug whitespace (jester 'with')))
(cold %with ;~(plug whitespace (jester 'with')))
(cold %delete ;~(plug whitespace (jester 'delete') whitespace (jester 'from')))
(cold %delete ;~(plug whitespace (jester 'delete')))
(cold %drop-database ;~(plug whitespace (jester 'drop') whitespace (jester 'database')))
@ -1478,8 +1533,8 @@
(cold %query ;~(plug whitespace ;~(pfix (jester 'select') (funk "select" (easy ' ')))))
(cold %revoke ;~(plug whitespace (jester 'revoke')))
(cold %truncate-table ;~(plug whitespace (jester 'truncate') whitespace (jester 'table')))
(cold %update ;~(pfix whitespace (jester 'update')))
==
=/ dummy ~|('Current database name is not a proper term' (scan (trip current-database) sym))
:: main loop
::
@ -1673,23 +1728,6 @@
==
%create-view
!!
%cte
~| "Cannot parse ctes {<q.q.command-nail>}"
~| "command-nail: {<command-nail>}"
=/ ctes-nail (parse-ctes [[1 1] q.q.command-nail])
~| "ctes-nail: {<ctes-nail>}"
=/ parsed (wonk ctes-nail)
=/ next-cursor
(get-next-cursor [script-position +<.command-nail p.q.u.+3:q.+3:ctes-nail])
~| "parsed: {<parsed>}"
~| "remainder: {<q.q.u.+3:q.+3.ctes-nail>}"
:: %= $
:: script q.q.u.+3.q:ctes-nail
:: script-position next-cursor
:: commands
:: [`command-ast`(produce-simple-cte parsed) commands]
:: ==
!!
%delete
=/ delete-nail (parse-delete [[1 1] q.q.command-nail])
=/ parsed (wonk delete-nail)
@ -1910,5 +1948,41 @@
commands
[`command-ast`(truncate-table:ast %truncate-table (wonk truncate-table-nail)) commands]
==
%update
=/ update-nail (parse-update [[1 1] q.q.command-nail])
=/ parsed (wonk update-nail)
=/ next-cursor
(get-next-cursor [script-position +<.command-nail p.q.u.+3:q.+3:update-nail])
%= $
script q.q.u.+3.q:update-nail
script-position next-cursor
commands
[`command-ast`(produce-update parsed) commands]
==
%with
~| "Cannot parse with {<q.q.command-nail>}"
~| "command-nail: {<command-nail>}"
=/ with-nail (parse-with [[1 1] q.q.command-nail])
~| "with-nail: {<with-nail>}"
=/ parsed (wonk with-nail)
=/ next-cursor
(get-next-cursor [script-position +<.command-nail p.q.u.+3:q.+3:with-nail])
~| "parsed: {<parsed>}"
~| "remainder: {<q.q.u.+3:q.+3.with-nail>}"
:: ?: =(%update +<.parsed)
:: %= $
:: script q.q.u.+3.q:with-nail
:: script-position next-cursor
:: commands
:: [`command-ast`(produce-update-with parsed) commands]
:: ==
:: %= $
:: script q.q.u.+3.q:with-nail
:: script-position next-cursor
:: commands
:: [`command-ast`(produce-simple-cte parsed) commands]
:: ==
!!
==
--

View File

@ -236,10 +236,10 @@
+$ update
$:
%update
(list cte-query)
table=qualified-object
columns=(list @t)
values=(list value-or-default)
(list cte-query)
predicate=(unit predicate)
==
+$ matching-action
@ -253,9 +253,9 @@
+$ merge
$:
%merge
(list cte-query)
source-table=qualified-object
target-table=qualified-object
(list cte-query)
on-predicate=predicate
when-matched=(unit matching)
when-not-matched-by-target=(unit matching)

View File

@ -2,7 +2,7 @@
/+ parse, *test
|%
::
:: delete
:: update
::
++ column-foo [%qualified-column qualifier=[%qualified-object ship=~ database='UNKNOWN' namespace='COLUMN-OR-CTE' name='foo'] column='foo' alias=~]
++ column-bar [%qualified-column qualifier=[%qualified-object ship=~ database='UNKNOWN' namespace='COLUMN-OR-CTE' name='bar'] column='bar' alias=~]
@ -16,53 +16,55 @@
[%qualified-column qualifier=[%qualified-object ship=~ database='UNKNOWN' namespace='COLUMN-OR-CTE' name='col3'] column='col3' alias=~]
++ col4
[%qualified-column qualifier=[%qualified-object ship=~ database='UNKNOWN' namespace='COLUMN-OR-CTE' name='col4'] column='col4' alias=~]
++ delete-pred
`[%eq [column-foo ~ ~] [column-bar ~ ~]]
++ cte-t1
[%cte name='t1' [%simple-query ~ [%scalars ~] ~ [%group-by ~] [%having ~] [%select top=~ bottom=~ distinct=%.n columns=~[all-columns]] ~]]
++ cte-foobar
[%cte name='foobar' [%simple-query [~ [%from object=[%query-object object=[%qualified-object ship=~ database='db1' namespace='dbo' name='foobar'] alias=~] joins=~]] [%scalars ~] `[%eq [col1 ~ ~] [[value-type=%ud value=2] ~ ~]] [%group-by ~] [%having ~] [%select top=~ bottom=~ distinct=%.n columns=~[col3 col4]] ~]]
++ cte-bar
[%cte name='bar' [%simple-query [~ [%from object=[%query-object object=[%qualified-object ship=~ database='db1' namespace='dbo' name='bar'] alias=~] joins=~]] [%scalars ~] `[%eq [col1 ~ ~] [col2 ~ ~]] [%group-by ~] [%having ~] [%select top=~ bottom=~ distinct=%.n columns=~[col2]] ~]]
++ foo-table
[%qualified-object ship=~ database='db1' namespace='dbo' name='foo']
++ one-eq-1 [%eq [[value-type=%ud value=1] ~ ~] [[value-type=%ud value=1] ~ ~]]
++ update-pred
[%and one-eq-1 [%eq [col2 ~ ~] [[value-type=%ud value=4] ~ ~]]]
::
:: delete from foo;delete foo
++ test-delete-01
=/ expected1 [[%delete table=[%qualified-object ship=~ database='db1' namespace='dbo' name='foo'] ~ ~]]
=/ expected2 [[%delete table=[%qualified-object ship=~ database='db1' namespace='dbo' name='foo'] ~ ~]]
:: update one column, no predicate
++ test-update-01
%+ expect-eq
!> ~[expected1 expected2]
!> (parse:parse(current-database 'db1') "delete from foo;delete foo")
!> ~[[%update table=foo-table columns=~['col1'] values=~[[value-type=%t value='hello']] ~ predicate=~]]
!> (parse:parse(current-database 'db1') "update foo set col1='hello'")
::
:: delete with predicate
++ test-delete-02
=/ expected [%delete table=[%qualified-object ship=~ database='db1' namespace='dbo' name='foo'] ~ delete-pred]
:: update two columns, no predicate
++ test-update-02
%+ expect-eq
!> ~[expected]
!> (parse:parse(current-database 'db1') "delete from foo where foo=bar")
!> ~[[%update table=foo-table columns=~['col3' 'col1'] values=~[[value-type=%t value='hello'] col2] ~ predicate=~]]
!> (parse:parse(current-database 'db1') "update foo set col1=col2, col3 = 'hello'")
::
:: delete with one cte and predicate
++ test-delete-03
=/ expected [%delete table=[%qualified-object ship=~ database='db1' namespace='dbo' name='foo'] ~[cte-t1] delete-pred]
:: update two columns, with predicate
++ test-update-03
%+ expect-eq
!> ~[expected]
!> (parse:parse(current-database 'db1') "delete from foo with (select *) as t1 where foo=bar")
!> ~[[%update table=foo-table columns=~['col3' 'col1'] values=~[[value-type=%t value='hello'] col2] ~ predicate=`update-pred]]
!> (parse:parse(current-database 'db1') "update foo set col1=col2, col3 = 'hello' where 1 = 1 and col2 = 4")
::
:: delete with two ctes and predicate
++ test-delete-04
=/ expected [%delete table=[%qualified-object ship=~ database='db1' namespace='dbo' name='foo'] ~[cte-t1 cte-foobar] delete-pred]
:: update with one cte and predicate
++ test-update-04
%+ expect-eq
!> ~[expected]
!> (parse:parse(current-database 'db1') "delete from foo with (select *) as t1, (from foobar where col1=2 select col3, col4) as foobar where foo=bar")
!> ~[[%update table=foo-table columns=~['col3' 'col1'] values=~[[value-type=%t value='hello'] col2] ~[cte-t1] predicate=`update-pred]]
!> (parse:parse(current-database 'db1') "update foo set col1=col2, col3 = 'hello' with (select *) as t1 where 1 = 1 and col2 = 4")
::
:: delete with three ctes and predicate
++ test-delete-05
=/ expected [%delete table=[%qualified-object ship=~ database='db1' namespace='dbo' name='foo'] ~[cte-t1 cte-foobar cte-bar] delete-pred]
:: update with three ctes and predicate
++ test-update-05
%+ expect-eq
!> ~[expected]
!> (parse:parse(current-database 'db1') "delete from foo with (select *) as t1, (from foobar where col1=2 select col3, col4) as foobar, (from bar where col1=col2 select col2) as bar where foo=bar")
!> ~[[%update table=foo-table columns=~['col3' 'col1'] values=~[[value-type=%t value='hello'] col2] ~[cte-t1 cte-foobar cte-bar] predicate=`update-pred]]
!> (parse:parse(current-database 'db1') "update foo set col1=col2, col3 = 'hello' with (select *) as t1, (from foobar where col1=2 select col3, col4) as foobar, (from bar where col1=col2 select col2) as bar where 1 = 1 and col2 = 4")
::
:: fail delete cte with no predicate
++ test-fail-delete-06
:: fail update cte with no predicate
++ test-fail-update-06
%- expect-fail
|. (parse:parse(current-database 'other-db') "delete from foo with (select *) as t1")
|. (parse:parse(current-database 'other-db') "update foo set col1=col2, col3 = 'hello' with (select *) as t1")
--

View File

@ -364,40 +364,41 @@
[%cte name='foobar' [%simple-query [~ [%from object=[%query-object object=[%qualified-object ship=~ database='db1' namespace='dbo' name='foobar'] alias=~] joins=~]] [%scalars ~] `[%eq [col1 ~ ~] [[value-type=%ud value=2] ~ ~]] [%group-by ~] [%having ~] [%select top=~ bottom=~ distinct=%.n columns=~[col3 col4]] ~]]
++ cte-bar
[%cte name='bar' [%simple-query [~ [%from object=[%query-object object=[%qualified-object ship=~ database='db1' namespace='dbo' name='bar'] alias=~] joins=~]] [%scalars ~] `[%eq [col1 ~ ~] [col2 ~ ~]] [%group-by ~] [%having ~] [%select top=~ bottom=~ distinct=%.n columns=~[col2]] ~]]
:: delete from foo;delete foo
++ foo-table
[%qualified-object ship=~ database='db1' namespace='dbo' name='foo']
::
:: delete from foo;delete foo
++ test-delete-01
=/ expected1 [[%delete table=[%qualified-object ship=~ database='db1' namespace='dbo' name='foo'] ~ ~]]
=/ expected2 [[%delete table=[%qualified-object ship=~ database='db1' namespace='dbo' name='foo'] ~ ~]]
=/ expected1 [[%delete table=foo-table ~ ~]]
=/ expected2 [[%delete table=foo-table ~ ~]]
%+ expect-eq
!> ~[expected1 expected2]
!> (parse:parse(current-database 'db1') "delete from foo;delete foo")
::
:: delete with predicate
++ test-delete-02
=/ expected [%delete table=[%qualified-object ship=~ database='db1' namespace='dbo' name='foo'] ~ delete-pred]
=/ expected [%delete table=foo-table ~ delete-pred]
%+ expect-eq
!> ~[expected]
!> (parse:parse(current-database 'db1') "delete from foo where foo=bar")
::
:: delete with one cte and predicate
++ test-delete-03
=/ expected [%delete table=[%qualified-object ship=~ database='db1' namespace='dbo' name='foo'] ~[cte-t1] delete-pred]
=/ expected [%delete table=foo-table ~[cte-t1] delete-pred]
%+ expect-eq
!> ~[expected]
!> (parse:parse(current-database 'db1') "delete from foo with (select *) as t1 where foo=bar")
::
:: delete with two ctes and predicate
++ test-delete-04
=/ expected [%delete table=[%qualified-object ship=~ database='db1' namespace='dbo' name='foo'] ~[cte-t1 cte-foobar] delete-pred]
=/ expected [%delete table=foo-table ~[cte-t1 cte-foobar] delete-pred]
%+ expect-eq
!> ~[expected]
!> (parse:parse(current-database 'db1') "delete from foo with (select *) as t1, (from foobar where col1=2 select col3, col4) as foobar where foo=bar")
::
:: delete with three ctes and predicate
++ test-delete-05
=/ expected [%delete table=[%qualified-object ship=~ database='db1' namespace='dbo' name='foo'] ~[cte-t1 cte-foobar cte-bar] delete-pred]
=/ expected [%delete table=foo-table ~[cte-t1 cte-foobar cte-bar] delete-pred]
%+ expect-eq
!> ~[expected]
!> (parse:parse(current-database 'db1') "delete from foo with (select *) as t1, (from foobar where col1=2 select col3, col4) as foobar, (from bar where col1=col2 select col2) as bar where foo=bar")
@ -978,9 +979,9 @@
:: from object and joins
::
++ from-foo
[~ [%from object=[%query-object object=[%qualified-object ship=~ database='db1' namespace='dbo' name='foo'] alias=~] joins=~]]
[~ [%from object=[%query-object object=foo-table alias=~] joins=~]]
++ from-foo-aliased
[~ [%from object=[%query-object object=[%qualified-object ship=~ database='db1' namespace='dbo' name='foo'] alias=[~ 'F1']] joins=~]]
[~ [%from object=[%query-object object=foo-table alias=[~ 'F1']] joins=~]]
++ simple-from-foo
[%simple-query from-foo [%scalars ~] ~ [%group-by ~] [%having ~] [%select top=[~ 10] bottom=~ distinct=%.y columns=~[[%qualified-object ship=~ database='ALL' namespace='ALL' name='ALL']]] ~]
++ aliased-from-foo
@ -988,29 +989,29 @@
++ joins-bar
~[[%joined-object join=%join object=[%query-object object=[%qualified-object ship=~ database='db1' namespace='dbo' name='bar'] alias=~] predicate=`[%eq [[value-type=%ud value=1] ~ ~] [[value-type=%ud value=1] ~ ~]]]]
++ from-foo-join-bar
[~ [%from object=[%query-object object=[%qualified-object ship=~ database='db1' namespace='dbo' name='foo'] alias=~] joins=joins-bar]]
[~ [%from object=[%query-object object=foo-table alias=~] joins=joins-bar]]
++ simple-from-foo-join-bar
[%simple-query from-foo-join-bar [%scalars ~] ~ [%group-by ~] [%having ~] [%select top=[~ 10] bottom=~ distinct=%.y columns=~[[%qualified-object ship=~ database='ALL' namespace='ALL' name='ALL']]] ~]
++ joins-bar-aliased
~[[%joined-object join=%join object=[%query-object object=[%qualified-object ship=~ database='db1' namespace='dbo' name='bar'] alias=[~ 'b1']] predicate=`[%eq [[value-type=%ud value=1] ~ ~] [[value-type=%ud value=1] ~ ~]]]]
++ from-foo-join-bar-aliased
[~ [%from object=[%query-object object=[%qualified-object ship=~ database='db1' namespace='dbo' name='foo'] alias=~] joins=joins-bar-aliased]]
[~ [%from object=[%query-object object=foo-table alias=~] joins=joins-bar-aliased]]
++ simple-from-foo-join-bar-aliased
[%simple-query from-foo-join-bar-aliased [%scalars ~] ~ [%group-by ~] [%having ~] [%select top=[~ 10] bottom=~ distinct=%.y columns=~[[%qualified-object ship=~ database='ALL' namespace='ALL' name='ALL']]] ~]
++ from-foo-aliased-join-bar-aliased
[~ [%from object=[%query-object object=[%qualified-object ship=~ database='db1' namespace='dbo' name='foo'] alias=[~ 'f1']] joins=joins-bar-aliased]]
[~ [%from object=[%query-object object=foo-table alias=[~ 'f1']] joins=joins-bar-aliased]]
++ aliased-from-foo-join-bar-aliased
[%simple-query from-foo-aliased-join-bar-aliased [%scalars ~] ~ [%group-by ~] [%having ~] [%select top=[~ 10] bottom=~ distinct=%.y columns=~[[%qualified-object ship=~ database='ALL' namespace='ALL' name='ALL']]] ~]
++ joins-bar-baz
~[[%joined-object join=%join object=[%query-object object=[%qualified-object ship=~ database='db1' namespace='dbo' name='bar'] alias=~] predicate=`[%eq [[value-type=%ud value=1] ~ ~] [[value-type=%ud value=1] ~ ~]]] [%joined-object join=%left-join object=[%query-object object=[%qualified-object ship=~ database='db1' namespace='dbo' name='baz'] alias=~] predicate=`[%eq [[value-type=%ud value=1] ~ ~] [[value-type=%ud value=1] ~ ~]]]]
++ from-foo-join-bar-baz
[~ [%from object=[%query-object object=[%qualified-object ship=~ database='db1' namespace='dbo' name='foo'] alias=~] joins=joins-bar-baz]]
[~ [%from object=[%query-object object=foo-table alias=~] joins=joins-bar-baz]]
++ simple-from-foo-join-bar-baz
[%simple-query from-foo-join-bar-baz [%scalars ~] ~ [%group-by ~] [%having ~] [%select top=[~ 10] bottom=~ distinct=%.y columns=~[[%qualified-object ship=~ database='ALL' namespace='ALL' name='ALL']]] ~]
++ aliased-joins-bar-baz
~[[%joined-object join=%join object=[%query-object object=[%qualified-object ship=~ database='db1' namespace='dbo' name='bar'] alias=[~ 'B1']] predicate=`[%eq [[value-type=%ud value=1] ~ ~] [[value-type=%ud value=1] ~ ~]]] [%joined-object join=%left-join object=[%query-object object=[%qualified-object ship=~ database='db1' namespace='dbo' name='baz'] alias=[~ 'b2']] predicate=`[%eq [[value-type=%ud value=1] ~ ~] [[value-type=%ud value=1] ~ ~]]]]
++ aliased-foo-join-bar-baz
[~ [%from object=[%query-object object=[%qualified-object ship=~ database='db1' namespace='dbo' name='foo'] alias=[~ 'f1']] joins=aliased-joins-bar-baz]]
[~ [%from object=[%query-object object=foo-table alias=[~ 'f1']] joins=aliased-joins-bar-baz]]
++ aliased-from-foo-join-bar-baz
[%simple-query aliased-foo-join-bar-baz [%scalars ~] ~ [%group-by ~] [%having ~] [%select top=[~ 10] bottom=~ distinct=%.y columns=~[[%qualified-object ship=~ database='ALL' namespace='ALL' name='ALL']]] ~]
::
@ -1806,7 +1807,7 @@
:: from foo select top, bottom, distinct, simple columns, trailing space, no internal space
++ test-select-18
=/ select "from foo select top 10 bottom 10 distinct x1,db.ns.table.col1,table-alias.name,db..table.col2,T1.foo,1,~zod,'cord' "
=/ from [~ [%from object=[%query-object object=[%qualified-object ship=~ database='db1' namespace='dbo' name='foo'] alias=~] joins=~]]
=/ from [~ [%from object=[%query-object object=foo-table alias=~] joins=~]]
=/ my-columns ~[[%qualified-column qualifier=[%qualified-object ship=~ database='UNKNOWN' namespace='COLUMN-OR-CTE' name='x1'] column='x1' alias=~] [%qualified-column qualifier=[%qualified-object ship=~ database='db' namespace='ns' name='table'] column='col1' alias=~] [%qualified-column qualifier=[%qualified-object ship=~ database='UNKNOWN' namespace='COLUMN' name='table-alias'] column='name' alias=~] [%qualified-column qualifier=[%qualified-object ship=~ database='db' namespace='dbo' name='table'] column='col2' alias=~] [%qualified-column qualifier=[%qualified-object ship=~ database='UNKNOWN' namespace='COLUMN' name='T1'] column='foo' alias=~] [%selected-value [value-type=%ud value=1] ~] [%selected-value [value-type=%p value=0] ~] [%selected-value [value-type=%t value='cord'] ~]]
%+ expect-eq
!> ~[[%simple-query from [%scalars ~] ~ [%group-by ~] [%having ~] [%select top=[~ 10] bottom=[~ 10] distinct=%.y columns=my-columns] ~]]
@ -2013,4 +2014,47 @@
%+ expect-eq
!> ~[[%simple-query from-foo [%scalars ~] ~ [%group-by ~] [%having ~] [%select top=~ bottom=~ distinct=%.n columns=~[all-columns]] order-by]]
!> (parse:parse(current-database 'db1') select)
::
:: update
::
++ one-eq-1
[%eq [[value-type=%ud value=1] ~ ~] [[value-type=%ud value=1] ~ ~]]
++ update-pred
[%and one-eq-1 [%eq [col2 ~ ~] [[value-type=%ud value=4] ~ ~]]]
::
:: update one column, no predicate
++ test-update-01
%+ expect-eq
!> ~[[%update table=foo-table columns=~['col1'] values=~[[value-type=%t value='hello']] ~ predicate=~]]
!> (parse:parse(current-database 'db1') "update foo set col1='hello'")
::
:: update two columns, no predicate
++ test-update-02
%+ expect-eq
!> ~[[%update table=foo-table columns=~['col3' 'col1'] values=~[[value-type=%t value='hello'] col2] ~ predicate=~]]
!> (parse:parse(current-database 'db1') "update foo set col1=col2, col3 = 'hello'")
::
:: update two columns, with predicate
++ test-update-03
%+ expect-eq
!> ~[[%update table=foo-table columns=~['col3' 'col1'] values=~[[value-type=%t value='hello'] col2] ~ predicate=`update-pred]]
!> (parse:parse(current-database 'db1') "update foo set col1=col2, col3 = 'hello' where 1 = 1 and col2 = 4")
::
:: update with one cte and predicate
++ test-update-04
%+ expect-eq
!> ~[[%update table=foo-table columns=~['col3' 'col1'] values=~[[value-type=%t value='hello'] col2] ~[cte-t1] predicate=`update-pred]]
!> (parse:parse(current-database 'db1') "update foo set col1=col2, col3 = 'hello' with (select *) as t1 where 1 = 1 and col2 = 4")
::
:: update with three ctes and predicate
++ test-update-05
%+ expect-eq
!> ~[[%update table=foo-table columns=~['col3' 'col1'] values=~[[value-type=%t value='hello'] col2] ~[cte-t1 cte-foobar cte-bar] predicate=`update-pred]]
!> (parse:parse(current-database 'db1') "update foo set col1=col2, col3 = 'hello' with (select *) as t1, (from foobar where col1=2 select col3, col4) as foobar, (from bar where col1=col2 select col2) as bar where 1 = 1 and col2 = 4")
::
:: fail update cte with no predicate
++ test-fail-update-06
%- expect-fail
|. (parse:parse(current-database 'other-db') "update foo set col1=col2, col3 = 'hello' with (select *) as t1")
--