Avoid unnecessary double wrapping of SELECT statement when used as single function parameter.

This commit is contained in:
go-jet 2021-10-21 13:35:37 +02:00
parent 22b2901336
commit d197956271
16 changed files with 97 additions and 77 deletions

View file

@ -375,9 +375,14 @@ type wrap struct {
expressions []Expression expressions []Expression
} }
func (n *wrap) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) { func (n *wrap) serialize(statementType StatementType, out *SQLBuilder, options ...SerializeOption) {
out.WriteString("(") out.WriteString("(")
serializeExpressionList(statement, n.expressions, ", ", out)
if len(n.expressions) == 1 {
options = append(options, NoWrap, Ident)
}
serializeExpressionList(statementType, n.expressions, ", ", out, options...)
out.WriteString(")") out.WriteString(")")
} }

View file

@ -7,8 +7,10 @@ type SerializeOption int
const ( const (
NoWrap SerializeOption = iota NoWrap SerializeOption = iota
SkipNewLine SkipNewLine
Ident
fallTroughOptions // fall trough options fallTroughOptions // fall trough options
ShortName ShortName
) )

View file

@ -195,10 +195,19 @@ func (s *statementImpl) serialize(statement StatementType, out *SQLBuilder, opti
out.IncreaseIdent() out.IncreaseIdent()
} }
if contains(options, Ident) {
out.IncreaseIdent()
}
for _, clause := range s.Clauses { for _, clause := range s.Clauses {
clause.Serialize(statement, out, FallTrough(options)...) clause.Serialize(statement, out, FallTrough(options)...)
} }
if contains(options, Ident) {
out.DecreaseIdent()
out.NewLine()
}
if !contains(options, NoWrap) { if !contains(options, NoWrap) {
out.DecreaseIdent() out.DecreaseIdent()
out.NewLine() out.NewLine()

View file

@ -21,14 +21,19 @@ func SerializeClauseList(statement StatementType, clauses []Serializer, out *SQL
} }
} }
func serializeExpressionList(statement StatementType, expressions []Expression, separator string, out *SQLBuilder) { func serializeExpressionList(
statement StatementType,
expressions []Expression,
separator string,
out *SQLBuilder,
options ...SerializeOption) {
for i, value := range expressions { for i, expression := range expressions {
if i > 0 { if i > 0 {
out.WriteString(separator) out.WriteString(separator)
} }
value.serialize(statement, out) expression.serialize(statement, out, options...)
} }
} }

View file

@ -7,7 +7,6 @@ import (
) )
func TestInvalidInsert(t *testing.T) { func TestInvalidInsert(t *testing.T) {
assertStatementSqlErr(t, table1.INSERT(table1Col1), "jet: VALUES or QUERY has to be specified for INSERT statement")
assertStatementSqlErr(t, table1.INSERT(nil).VALUES(1), "jet: nil column in columns list") assertStatementSqlErr(t, table1.INSERT(nil).VALUES(1), "jet: nil column in columns list")
} }

View file

@ -46,33 +46,33 @@ func TestExists(t *testing.T) {
func TestIN(t *testing.T) { func TestIN(t *testing.T) {
assertSerialize(t, Float(1.11).IN(table1.SELECT(table1Col1)), assertSerialize(t, Float(1.11).IN(table1.SELECT(table1Col1)),
`($1 IN (( `($1 IN (
SELECT table1.col1 AS "table1.col1" SELECT table1.col1 AS "table1.col1"
FROM db.table1 FROM db.table1
)))`, float64(1.11)) ))`, float64(1.11))
assertSerialize(t, ROW(Int(12), table1Col1).IN(table2.SELECT(table2Col3, table3Col1)), assertSerialize(t, ROW(Int(12), table1Col1).IN(table2.SELECT(table2Col3, table3Col1)),
`(ROW($1, table1.col1) IN (( `(ROW($1, table1.col1) IN (
SELECT table2.col3 AS "table2.col3", SELECT table2.col3 AS "table2.col3",
table3.col1 AS "table3.col1" table3.col1 AS "table3.col1"
FROM db.table2 FROM db.table2
)))`, int64(12)) ))`, int64(12))
} }
func TestNOT_IN(t *testing.T) { func TestNOT_IN(t *testing.T) {
assertSerialize(t, Float(1.11).NOT_IN(table1.SELECT(table1Col1)), assertSerialize(t, Float(1.11).NOT_IN(table1.SELECT(table1Col1)),
`($1 NOT IN (( `($1 NOT IN (
SELECT table1.col1 AS "table1.col1" SELECT table1.col1 AS "table1.col1"
FROM db.table1 FROM db.table1
)))`, float64(1.11)) ))`, float64(1.11))
assertSerialize(t, ROW(Int(12), table1Col1).NOT_IN(table2.SELECT(table2Col3, table3Col1)), assertSerialize(t, ROW(Int(12), table1Col1).NOT_IN(table2.SELECT(table2Col3, table3Col1)),
`(ROW($1, table1.col1) NOT IN (( `(ROW($1, table1.col1) NOT IN (
SELECT table2.col3 AS "table2.col3", SELECT table2.col3 AS "table2.col3",
table3.col1 AS "table3.col1" table3.col1 AS "table3.col1"
FROM db.table2 FROM db.table2
)))`, int64(12)) ))`, int64(12))
} }
func TestReservedWordEscaped(t *testing.T) { func TestReservedWordEscaped(t *testing.T) {

View file

@ -104,18 +104,18 @@ func TestExpressionOperators(t *testing.T) {
SELECT all_types.'integer' IS NULL AS "result.is_null", SELECT all_types.'integer' IS NULL AS "result.is_null",
all_types.date_ptr IS NOT NULL AS "result.is_not_null", all_types.date_ptr IS NOT NULL AS "result.is_not_null",
(all_types.small_int_ptr IN (?, ?)) AS "result.in", (all_types.small_int_ptr IN (?, ?)) AS "result.in",
(all_types.small_int_ptr IN (( (all_types.small_int_ptr IN (
SELECT all_types.'integer' AS "all_types.integer" SELECT all_types.'integer' AS "all_types.integer"
FROM test_sample.all_types FROM test_sample.all_types
))) AS "result.in_select", )) AS "result.in_select",
(CURRENT_USER()) AS "result.raw", (CURRENT_USER()) AS "result.raw",
(? + COALESCE(all_types.small_int_ptr, 0) + ?) AS "result.raw_arg", (? + COALESCE(all_types.small_int_ptr, 0) + ?) AS "result.raw_arg",
(? + all_types.integer + ? + ? + ? + ?) AS "result.raw_arg2", (? + all_types.integer + ? + ? + ? + ?) AS "result.raw_arg2",
(all_types.small_int_ptr NOT IN (?, ?, NULL)) AS "result.not_in", (all_types.small_int_ptr NOT IN (?, ?, NULL)) AS "result.not_in",
(all_types.small_int_ptr NOT IN (( (all_types.small_int_ptr NOT IN (
SELECT all_types.'integer' AS "all_types.integer" SELECT all_types.'integer' AS "all_types.integer"
FROM test_sample.all_types FROM test_sample.all_types
))) AS "result.not_in_select" )) AS "result.not_in_select"
FROM test_sample.all_types FROM test_sample.all_types
LIMIT ?; LIMIT ?;
`, "'", "`", -1), int64(11), int64(22), 78, 56, 11, 22, 11, 33, 44, int64(11), int64(22), int64(2)) `, "'", "`", -1), int64(11), int64(22), 78, 56, 11, 22, 11, 33, 44, int64(11), int64(22), int64(2))

View file

@ -278,7 +278,7 @@ ON DUPLICATE KEY UPDATE id = (id + ?),
err := SELECT(Link.AllColumns). err := SELECT(Link.AllColumns).
FROM(Link). FROM(Link).
WHERE(Link.ID.EQ(Int(int64(randId)).ADD(Int(11)))). WHERE(Link.ID.EQ(Int32(randId).ADD(Int(11)))).
Query(db, &newLinks) Query(db, &newLinks)
require.NoError(t, err) require.NoError(t, err)

View file

@ -121,7 +121,7 @@ func TestUpdateWithModelData(t *testing.T) {
stmt := Link. stmt := Link.
UPDATE(Link.AllColumns). UPDATE(Link.AllColumns).
MODEL(link). MODEL(link).
WHERE(Link.ID.EQ(Int(int64(link.ID)))) WHERE(Link.ID.EQ(Int32(link.ID)))
expectedSQL := ` expectedSQL := `
UPDATE test_sample.link UPDATE test_sample.link
@ -131,7 +131,7 @@ SET id = ?,
description = ? description = ?
WHERE link.id = ?; WHERE link.id = ?;
` `
testutils.AssertStatementSql(t, stmt, expectedSQL, int32(201), "http://www.duckduckgo.com", "DuckDuckGo", nil, int64(201)) testutils.AssertStatementSql(t, stmt, expectedSQL, int32(201), "http://www.duckduckgo.com", "DuckDuckGo", nil, int32(201))
testutils.AssertExec(t, stmt, db) testutils.AssertExec(t, stmt, db)
requireLogged(t, stmt) requireLogged(t, stmt)
@ -152,7 +152,7 @@ func TestUpdateWithModelDataAndPredefinedColumnList(t *testing.T) {
stmt := Link. stmt := Link.
UPDATE(updateColumnList). UPDATE(updateColumnList).
MODEL(link). MODEL(link).
WHERE(Link.ID.EQ(Int(int64(link.ID)))) WHERE(Link.ID.EQ(Int32(link.ID)))
var expectedSQL = ` var expectedSQL = `
UPDATE test_sample.link UPDATE test_sample.link
@ -161,9 +161,8 @@ SET description = NULL,
url = 'http://www.duckduckgo.com' url = 'http://www.duckduckgo.com'
WHERE link.id = 201; WHERE link.id = 201;
` `
//fmt.Println(stmt.DebugSql())
testutils.AssertDebugStatementSql(t, stmt, expectedSQL, nil, "DuckDuckGo", "http://www.duckduckgo.com", int64(201)) testutils.AssertDebugStatementSql(t, stmt, expectedSQL, nil, "DuckDuckGo", "http://www.duckduckgo.com", int32(201))
testutils.AssertExec(t, stmt, db) testutils.AssertExec(t, stmt, db)
requireLogged(t, stmt) requireLogged(t, stmt)
@ -181,7 +180,7 @@ func TestUpdateWithModelDataAndMutableColumns(t *testing.T) {
stmt := Link. stmt := Link.
UPDATE(Link.MutableColumns). UPDATE(Link.MutableColumns).
MODEL(link). MODEL(link).
WHERE(Link.ID.EQ(Int(int64(link.ID)))) WHERE(Link.ID.EQ(Int32(link.ID)))
var expectedSQL = ` var expectedSQL = `
UPDATE test_sample.link UPDATE test_sample.link
@ -192,7 +191,7 @@ WHERE link.id = 201;
` `
//fmt.Println(stmt.DebugSql()) //fmt.Println(stmt.DebugSql())
testutils.AssertDebugStatementSql(t, stmt, expectedSQL, "http://www.duckduckgo.com", "DuckDuckGo", nil, int64(201)) testutils.AssertDebugStatementSql(t, stmt, expectedSQL, "http://www.duckduckgo.com", "DuckDuckGo", nil, int32(201))
testutils.AssertExec(t, stmt, db) testutils.AssertExec(t, stmt, db)
} }

View file

@ -241,18 +241,18 @@ func TestExpressionOperators(t *testing.T) {
SELECT all_types.integer IS NULL AS "result.is_null", SELECT all_types.integer IS NULL AS "result.is_null",
all_types.date_ptr IS NOT NULL AS "result.is_not_null", all_types.date_ptr IS NOT NULL AS "result.is_not_null",
(all_types.small_int_ptr IN ($1, $2)) AS "result.in", (all_types.small_int_ptr IN ($1, $2)) AS "result.in",
(all_types.small_int_ptr IN (( (all_types.small_int_ptr IN (
SELECT all_types.integer AS "all_types.integer" SELECT all_types.integer AS "all_types.integer"
FROM test_sample.all_types FROM test_sample.all_types
))) AS "result.in_select", )) AS "result.in_select",
(CURRENT_USER) AS "result.raw", (CURRENT_USER) AS "result.raw",
($3 + COALESCE(all_types.small_int_ptr, 0) + $4) AS "result.raw_arg", ($3 + COALESCE(all_types.small_int_ptr, 0) + $4) AS "result.raw_arg",
($5 + all_types.integer + $6 + $5 + $7 + $8) AS "result.raw_arg2", ($5 + all_types.integer + $6 + $5 + $7 + $8) AS "result.raw_arg2",
(all_types.small_int_ptr NOT IN ($9, $10, NULL)) AS "result.not_in", (all_types.small_int_ptr NOT IN ($9, $10, NULL)) AS "result.not_in",
(all_types.small_int_ptr NOT IN (( (all_types.small_int_ptr NOT IN (
SELECT all_types.integer AS "all_types.integer" SELECT all_types.integer AS "all_types.integer"
FROM test_sample.all_types FROM test_sample.all_types
))) AS "result.not_in_select" )) AS "result.not_in_select"
FROM test_sample.all_types FROM test_sample.all_types
LIMIT $11; LIMIT $11;
`, int64(11), int64(22), 78, 56, 11, 22, 33, 44, int64(11), int64(22), int64(2)) `, int64(11), int64(22), 78, 56, 11, 22, 33, 44, int64(11), int64(22), int64(2))

View file

@ -5,6 +5,7 @@ import (
"io/ioutil" "io/ioutil"
"os" "os"
"os/exec" "os/exec"
"path/filepath"
"reflect" "reflect"
"testing" "testing"
@ -368,16 +369,16 @@ func newActorInfoTableImpl(schemaName, tableName, alias string) actorInfoTable {
` `
func TestGeneratedAllTypesSQLBuilderFiles(t *testing.T) { func TestGeneratedAllTypesSQLBuilderFiles(t *testing.T) {
enumDir := testRoot + ".gentestdata/jetdb/test_sample/enum/" enumDir := filepath.Join(testRoot, "/.gentestdata/jetdb/test_sample/enum/")
modelDir := testRoot + ".gentestdata/jetdb/test_sample/model/" modelDir := filepath.Join(testRoot, "/.gentestdata/jetdb/test_sample/model/")
tableDir := testRoot + ".gentestdata/jetdb/test_sample/table/" tableDir := filepath.Join(testRoot, "/.gentestdata/jetdb/test_sample/table/")
enumFiles, err := ioutil.ReadDir(enumDir) enumFiles, err := ioutil.ReadDir(enumDir)
require.NoError(t, err) require.NoError(t, err)
testutils.AssertFileNamesEqual(t, enumFiles, "mood.go", "level.go") testutils.AssertFileNamesEqual(t, enumFiles, "mood.go", "level.go")
testutils.AssertFileContent(t, enumDir+"mood.go", moodEnumContent) testutils.AssertFileContent(t, enumDir+"/mood.go", moodEnumContent)
testutils.AssertFileContent(t, enumDir+"level.go", levelEnumContent) testutils.AssertFileContent(t, enumDir+"/level.go", levelEnumContent)
modelFiles, err := ioutil.ReadDir(modelDir) modelFiles, err := ioutil.ReadDir(modelDir)
require.NoError(t, err) require.NoError(t, err)
@ -385,7 +386,7 @@ func TestGeneratedAllTypesSQLBuilderFiles(t *testing.T) {
testutils.AssertFileNamesEqual(t, modelFiles, "all_types.go", "all_types_view.go", "employee.go", "link.go", testutils.AssertFileNamesEqual(t, modelFiles, "all_types.go", "all_types_view.go", "employee.go", "link.go",
"mood.go", "person.go", "person_phone.go", "weird_names_table.go", "level.go", "user.go", "floats.go") "mood.go", "person.go", "person_phone.go", "weird_names_table.go", "level.go", "user.go", "floats.go")
testutils.AssertFileContent(t, modelDir+"all_types.go", allTypesModelContent) testutils.AssertFileContent(t, modelDir+"/all_types.go", allTypesModelContent)
tableFiles, err := ioutil.ReadDir(tableDir) tableFiles, err := ioutil.ReadDir(tableDir)
require.NoError(t, err) require.NoError(t, err)
@ -393,7 +394,7 @@ func TestGeneratedAllTypesSQLBuilderFiles(t *testing.T) {
testutils.AssertFileNamesEqual(t, tableFiles, "all_types.go", "employee.go", "link.go", testutils.AssertFileNamesEqual(t, tableFiles, "all_types.go", "employee.go", "link.go",
"person.go", "person_phone.go", "weird_names_table.go", "user.go", "floats.go") "person.go", "person_phone.go", "weird_names_table.go", "user.go", "floats.go")
testutils.AssertFileContent(t, tableDir+"all_types.go", allTypesTableContent) testutils.AssertFileContent(t, tableDir+"/all_types.go", allTypesTableContent)
} }
var moodEnumContent = ` var moodEnumContent = `

View file

@ -140,8 +140,7 @@ ON CONFLICT ON CONSTRAINT employee_pkey DO NOTHING;
Link.ID.SET(Link.EXCLUDED.ID), Link.ID.SET(Link.EXCLUDED.ID),
Link.URL.SET(String("http://www.postgresqltutorial2.com")), Link.URL.SET(String("http://www.postgresqltutorial2.com")),
), ),
). ).RETURNING(Link.AllColumns)
RETURNING(Link.AllColumns)
testutils.AssertStatementSql(t, stmt, ` testutils.AssertStatementSql(t, stmt, `
INSERT INTO test_sample.link (id, url, name, description) INSERT INTO test_sample.link (id, url, name, description)

View file

@ -4,10 +4,9 @@ import (
"context" "context"
"database/sql" "database/sql"
"fmt" "fmt"
"github.com/go-jet/jet/v2/tests/internal/utils/repo"
"math/rand" "math/rand"
"os" "os"
"os/exec"
"strings"
"testing" "testing"
"time" "time"
@ -53,13 +52,7 @@ func TestMain(m *testing.M) {
} }
func setTestRoot() { func setTestRoot() {
cmd := exec.Command("git", "rev-parse", "--show-toplevel") testRoot = repo.GetTestsDirPath()
byteArr, err := cmd.Output()
if err != nil {
panic(err)
}
testRoot = strings.TrimSpace(string(byteArr)) + "/tests/"
} }
var loggedSQL string var loggedSQL string

View file

@ -75,11 +75,12 @@ LIMIT 30;
query := SELECT( query := SELECT(
Payment.AllColumns, Payment.AllColumns,
Customer.AllColumns, Customer.AllColumns,
). ).FROM(
FROM(Payment. Payment.
INNER_JOIN(Customer, Payment.CustomerID.EQ(Customer.CustomerID))). INNER_JOIN(Customer, Payment.CustomerID.EQ(Customer.CustomerID)),
ORDER_BY(Payment.PaymentID.ASC()). ).ORDER_BY(
LIMIT(30) Payment.PaymentID.ASC(),
).LIMIT(30)
testutils.AssertDebugStatementSql(t, query, expectedSQL, int64(30)) testutils.AssertDebugStatementSql(t, query, expectedSQL, int64(30))

View file

@ -259,14 +259,14 @@ func TestUpdateWithModelData(t *testing.T) {
stmt := Link. stmt := Link.
UPDATE(Link.AllColumns). UPDATE(Link.AllColumns).
MODEL(link). MODEL(link).
WHERE(Link.ID.EQ(Int(int64(link.ID)))) WHERE(Link.ID.EQ(Int32(link.ID)))
expectedSQL := ` expectedSQL := `
UPDATE test_sample.link UPDATE test_sample.link
SET (id, url, name, description) = (201, 'http://www.duckduckgo.com', 'DuckDuckGo', NULL) SET (id, url, name, description) = (201, 'http://www.duckduckgo.com', 'DuckDuckGo', NULL)
WHERE link.id = 201; WHERE link.id = 201;
` `
testutils.AssertDebugStatementSql(t, stmt, expectedSQL, int32(201), "http://www.duckduckgo.com", "DuckDuckGo", nil, int64(201)) testutils.AssertDebugStatementSql(t, stmt, expectedSQL, int32(201), "http://www.duckduckgo.com", "DuckDuckGo", nil, int32(201))
AssertExec(t, stmt, 1) AssertExec(t, stmt, 1)
} }
@ -286,14 +286,14 @@ func TestUpdateWithModelDataAndPredefinedColumnList(t *testing.T) {
stmt := Link. stmt := Link.
UPDATE(updateColumnList). UPDATE(updateColumnList).
MODEL(link). MODEL(link).
WHERE(Link.ID.EQ(Int(int64(link.ID)))) WHERE(Link.ID.EQ(Int32(link.ID)))
var expectedSQL = ` var expectedSQL = `
UPDATE test_sample.link UPDATE test_sample.link
SET (description, name, url) = (NULL, 'DuckDuckGo', 'http://www.duckduckgo.com') SET (description, name, url) = (NULL, 'DuckDuckGo', 'http://www.duckduckgo.com')
WHERE link.id = 201; WHERE link.id = 201;
` `
testutils.AssertDebugStatementSql(t, stmt, expectedSQL, nil, "DuckDuckGo", "http://www.duckduckgo.com", int64(201)) testutils.AssertDebugStatementSql(t, stmt, expectedSQL, nil, "DuckDuckGo", "http://www.duckduckgo.com", int32(201))
AssertExec(t, stmt, 1) AssertExec(t, stmt, 1)
} }

View file

@ -22,14 +22,17 @@ func TestWithRegionalSales(t *testing.T) {
SELECT( SELECT(
Orders.ShipRegion, Orders.ShipRegion,
SUM(OrderDetails.Quantity).AS(regionalSalesTotalSales.Name()), SUM(OrderDetails.Quantity).AS(regionalSalesTotalSales.Name()),
). ).FROM(
FROM(Orders.INNER_JOIN(OrderDetails, OrderDetails.OrderID.EQ(Orders.OrderID))). Orders.INNER_JOIN(OrderDetails, OrderDetails.OrderID.EQ(Orders.OrderID)),
GROUP_BY(Orders.ShipRegion), ).GROUP_BY(Orders.ShipRegion),
), ),
topRegion.AS( topRegion.AS(
SELECT(regionalSalesShipRegion). SELECT(
FROM(regionalSales). regionalSalesShipRegion,
WHERE(regionalSalesTotalSales.GT( ).FROM(
regionalSales,
).WHERE(
regionalSalesTotalSales.GT(
IntExp( IntExp(
SELECT(SUM(regionalSalesTotalSales)). SELECT(SUM(regionalSalesTotalSales)).
FROM(regionalSales), FROM(regionalSales),
@ -43,13 +46,17 @@ func TestWithRegionalSales(t *testing.T) {
OrderDetails.ProductID, OrderDetails.ProductID,
COUNT(STAR).AS("product_units"), COUNT(STAR).AS("product_units"),
SUM(OrderDetails.Quantity).AS("product_sales"), SUM(OrderDetails.Quantity).AS("product_sales"),
). ).FROM(
FROM(Orders.INNER_JOIN(OrderDetails, Orders.OrderID.EQ(OrderDetails.OrderID))). Orders.
WHERE(Orders.ShipRegion.IN( INNER_JOIN(OrderDetails, Orders.OrderID.EQ(OrderDetails.OrderID)),
topRegion.SELECT(topRegionShipRegion)), ).WHERE(
). Orders.ShipRegion.IN(topRegion.SELECT(topRegionShipRegion)),
GROUP_BY(Orders.ShipRegion, OrderDetails.ProductID). ).GROUP_BY(
ORDER_BY(SUM(OrderDetails.Quantity).DESC()), Orders.ShipRegion,
OrderDetails.ProductID,
).ORDER_BY(
SUM(OrderDetails.Quantity).DESC(),
),
) )
//fmt.Println(stmt.DebugSql()) //fmt.Println(stmt.DebugSql())
@ -75,10 +82,10 @@ SELECT orders.ship_region AS "orders.ship_region",
SUM(order_details.quantity) AS "product_sales" SUM(order_details.quantity) AS "product_sales"
FROM northwind.orders FROM northwind.orders
INNER JOIN northwind.order_details ON (orders.order_id = order_details.order_id) INNER JOIN northwind.order_details ON (orders.order_id = order_details.order_id)
WHERE orders.ship_region IN (( WHERE orders.ship_region IN (
SELECT top_region."orders.ship_region" AS "orders.ship_region" SELECT top_region."orders.ship_region" AS "orders.ship_region"
FROM top_region FROM top_region
)) )
GROUP BY orders.ship_region, order_details.product_id GROUP BY orders.ship_region, order_details.product_id
ORDER BY SUM(order_details.quantity) DESC; ORDER BY SUM(order_details.quantity) DESC;
`) `)
@ -141,19 +148,19 @@ func TestWithStatementDeleteAndInsert(t *testing.T) {
testutils.AssertStatementSql(t, stmt, ` testutils.AssertStatementSql(t, stmt, `
WITH remove_discontinued_orders AS ( WITH remove_discontinued_orders AS (
DELETE FROM northwind.order_details DELETE FROM northwind.order_details
WHERE order_details.product_id IN (( WHERE order_details.product_id IN (
SELECT products.product_id AS "products.product_id" SELECT products.product_id AS "products.product_id"
FROM northwind.products FROM northwind.products
WHERE products.discontinued = $1 WHERE products.discontinued = $1
)) )
RETURNING order_details.product_id AS "order_details.product_id" RETURNING order_details.product_id AS "order_details.product_id"
),update_discontinued_price AS ( ),update_discontinued_price AS (
UPDATE northwind.products UPDATE northwind.products
SET unit_price = $2 SET unit_price = $2
WHERE products.product_id IN (( WHERE products.product_id IN (
SELECT remove_discontinued_orders."order_details.product_id" AS "order_details.product_id" SELECT remove_discontinued_orders."order_details.product_id" AS "order_details.product_id"
FROM remove_discontinued_orders FROM remove_discontinued_orders
)) )
RETURNING products.product_id AS "products.product_id", RETURNING products.product_id AS "products.product_id",
products.product_name AS "products.product_name", products.product_name AS "products.product_name",
products.supplier_id AS "products.supplier_id", products.supplier_id AS "products.supplier_id",