diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index a397506dcf..23868ae110 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -60,4 +60,5 @@ CAY-2801 Incorrect equals() implementation in IdGenerationMarker could cause dat CAY-2806 Incorrect processing of unicode escape syntax in JSON CAY-2809 Cayenne Expression grammar doesn't allow custom function as an argument for string functions CAY-2810 Can't use custom operator expression with aggregate functions -CAY-2813 Regression: Constants.CI_PROPERTY flag is no longer working for MySQL \ No newline at end of file +CAY-2813 Regression: Constants.CI_PROPERTY flag is no longer working for MySQL +CAY-2815 Incorrect translation of aliased expression \ No newline at end of file diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/FunctionNodeBuilder.java b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/FunctionNodeBuilder.java index 5146431a68..0623965b9b 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/FunctionNodeBuilder.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/FunctionNodeBuilder.java @@ -42,6 +42,14 @@ public FunctionNodeBuilder as(String alias) { return this; } + public OrderingNodeBuilder desc() { + return new OrderingNodeBuilder(this).desc(); + } + + public OrderingNodeBuilder asc() { + return new OrderingNodeBuilder(this).asc(); + } + @Override public Node build() { Node functionNode = new FunctionNode(functionName, alias, true); diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/AliasedNode.java b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/AliasedNode.java index f6cf638e9a..63a92e7f61 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/AliasedNode.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/AliasedNode.java @@ -61,7 +61,7 @@ public void appendChildrenEnd(QuotingAppendable buffer) { if(skipContent()){ return; } - buffer.append(" AS ").append(alias); + buffer.append(" ").append(alias); } public String getAlias() { @@ -77,6 +77,13 @@ private boolean skipContent() { } parent = parent.getParent(); } + + // check if we have subselect as a child + for(Node child : children) { + if(child.getType() == NodeType.SELECT) { + return false; + } + } return true; } } diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/FunctionNode.java b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/FunctionNode.java index 390287ae5d..8920c860bb 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/FunctionNode.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/FunctionNode.java @@ -89,7 +89,7 @@ public void appendChildrenEnd(QuotingAppendable buffer) { } if (alias != null) { - buffer.append(" AS ").appendQuoted(alias); + buffer.append(" ").appendQuoted(alias); } } diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/NodeType.java b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/NodeType.java index f463c077d9..c02019af76 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/NodeType.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/NodeType.java @@ -39,5 +39,6 @@ public enum NodeType { UPDATE_SET, INSERT_COLUMNS, INSERT_VALUES, - ORDER_BY + ORDER_BY, + SELECT } diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/SelectNode.java b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/SelectNode.java index 0afc84042d..7871ca03a0 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/SelectNode.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/access/sqlbuilder/sqltree/SelectNode.java @@ -45,4 +45,9 @@ public void appendChildrenEnd(QuotingAppendable buffer) { public Node copy() { return new SelectNode(); } + + @Override + public NodeType getType() { + return NodeType.SELECT; + } } diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/sqlbuilder/SelectBuilderTest.java b/cayenne-server/src/test/java/org/apache/cayenne/access/sqlbuilder/SelectBuilderTest.java index 9d11f417a7..dc94abb5a4 100644 --- a/cayenne-server/src/test/java/org/apache/cayenne/access/sqlbuilder/SelectBuilderTest.java +++ b/cayenne-server/src/test/java/org/apache/cayenne/access/sqlbuilder/SelectBuilderTest.java @@ -120,7 +120,7 @@ public void testValidSelectCaseWhen() { "WHEN ( ( Quantity > 30 ) AND ( Quantity < 100 ) ) THEN 'The quantity from 30 to 100' " + "WHEN ( Quantity = 30 ) THEN 'The quantity is 30' " + "ELSE 'The quantity is under 30' " + - "END AS QuantityText " + + "END QuantityText " + "FROM OrderDetails", node); } @@ -133,6 +133,29 @@ public void testInvalidSelectCaseWhen() { .from(table("OrderDetails")); } + @Test + public void testQueryAlias() { + SelectBuilder innerSelect = select(table("p").column("PAINTING_TITLE")) + .from(table("PAINTING").as("p")); + Node node = select(table("t").column("*")) + .from(aliased(innerSelect, "t")) + .build(); + + assertThat(node, instanceOf(SelectNode.class)); + assertSQL("SELECT t.* FROM (SELECT p.PAINTING_TITLE FROM PAINTING p) t", node); + } + + @Test + public void testFunctionAlias() { + Node node = select(function("test", table("p").column("PAINTING_TITLE")).as("f")) + .from(table("PAINTING").as("p")) + .orderBy(function("test", table("p").column("PAINTING_TITLE")).as("f")) + .build(); + + assertThat(node, instanceOf(SelectNode.class)); + assertSQL("SELECT test( p.PAINTING_TITLE ) f FROM PAINTING p ORDER BY f", node); + } + @Test public void testComplexQuery() { Node node = select( @@ -155,11 +178,11 @@ public void testComplexQuery() { ) .groupBy(table("a").column("ARTIST_ID")) .having(not(count(table("p").column("PAINTING_TITLE")).gt(value(3)))) - .orderBy(column("p_count").desc(), column("a_id").asc()) + .orderBy(count(table("p").column("PAINTING_TITLE")).as("p_count").desc(), column("a_id").asc()) .build(); assertThat(node, instanceOf(SelectNode.class)); assertSQL("SELECT DISTINCT" + - " a.ARTIST_ID a_id, COUNT( p.PAINTING_TITLE ) AS p_count" + + " a.ARTIST_ID a_id, COUNT( p.PAINTING_TITLE ) p_count" + " FROM ARTIST a" + " LEFT JOIN PAINTING p ON ( a.ARTIST_ID = p.ARTIST_ID ) AND ( p.ESTIMATED_PRICE > 10 )" + " WHERE ( ( ( a.ARTIST_NAME = 'Picasso' )" +