[jira] [Updated] (CAY-2814) Select query iterator() and batchIterator() methods return incorrect results

2024-02-29 Thread Nikita Timofeev (Jira)


 [ 
https://issues.apache.org/jira/browse/CAY-2814?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Nikita Timofeev updated CAY-2814:
-
Fix Version/s: (was: 4.2.1)

> Select query iterator() and batchIterator() methods return incorrect results
> 
>
> Key: CAY-2814
> URL: https://issues.apache.org/jira/browse/CAY-2814
> Project: Cayenne
>  Issue Type: Bug
>  Components: Core Library
>Affects Versions: 4.1.1, 4.2.RC1, 4.2
>Reporter: Nikita Timofeev
>Assignee: Nikita Timofeev
>Priority: Major
> Fix For: 5.0-M1
>
>  Time Spent: 40m
>  Remaining Estimate: 0h
>
> Iterated queries can handle only basic results like single entity, 
> {{Object[]}} and {{DataRow}}
> everything else is missing in the processing.
> This affects ColumnQuery most as it can return many more variants.
> What variants are broken:
> * all selects: joint prefetches
> * column query: several entities or entity + some other fields
> * column query: embeddables
> * column query: map function (see CAY-2812)
> * maybe something else (?)



--
This message was sent by Atlassian Jira
(v8.20.10#820010)


[jira] [Closed] (CAY-2841) Multi column ColumnSelect with SHARED_CACHE fails after 1st select

2024-02-29 Thread Nikita Timofeev (Jira)


 [ 
https://issues.apache.org/jira/browse/CAY-2841?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Nikita Timofeev closed CAY-2841.

Resolution: Fixed

*4.2*: 
https://github.com/apache/cayenne/commit/c987980c7229782cd813966d6dfc56a67bccea15

> Multi column ColumnSelect with SHARED_CACHE fails after 1st select
> --
>
> Key: CAY-2841
> URL: https://issues.apache.org/jira/browse/CAY-2841
> Project: Cayenne
>  Issue Type: Bug
>Affects Versions: 4.2
>Reporter: Jurgen Doll
>Assignee: Nikita Timofeev
>Priority: Minor
> Fix For: 4.2.1, 5.0-M1
>
>  Time Spent: 20m
>  Remaining Estimate: 0h
>
> Adding the following test case to 
> {color:#00}{color:#00}ColumnSelectIT{color}{color} shows the problem:
>  
> {color:#00} {color}{color:#646464}@{color}{color:#00}Test{color}
> {color:#00} {color}{color:#7f0055}public{color}{color:#00} 
> {color}{color:#7f0055}void{color}{color:#00} testSharedCache() 
> {color}{color:#7f0055}throws{color}{color:#00} Exception {{color}
> {color:#00} ColumnSelect colQry = ObjectSelect.query( 
> Artist.{color}{color:#7f0055}class{color}{color:#00} ){color}
> {color:#00} .columns( Artist.ARTIST_NAME, Artist.DATE_OF_BIRTH ){color}
> {color:#00} .cacheStrategy( QueryCacheStrategy.SHARED_CACHE );{color}
> {color:#00} {color}
> {color:#00} List result = colQry.select(context);{color}
> {color:#00} assertEquals(20, result.size());{color}
>  
> {color:#00} {color}{color:#3f7f5f}// Next line fails with 
> UnsupportedOperationException{color}
> {color:#00} List result2 = colQry.select(context);{color}
> {color:#00} assertEquals(20, result.size());{color}
> {color:#00} }{color}
>  
> Stacktrace:
>  
> {color:#ff}Exception in thread "JavaFX Application Thread" 
> {color}{color:#0066cc}java.lang.UnsupportedOperationException{color}
> {color:#ff} at 
> java.base/java.util.Collections$UnmodifiableCollection.removeIf({color}{color:#0066cc}Collections.java:1120{color}{color:#ff}){color}
> {color:#ff} at 
> org.apache.cayenne.access.DataDomainQueryAction$MixedConversionStrategy.convert({color}{color:#0066cc}DataDomainQueryAction.java:818{color}{color:#ff}){color}
> {color:#ff} at 
> org.apache.cayenne.access.DataDomainQueryAction.interceptObjectConversion({color}{color:#0066cc}DataDomainQueryAction.java:507{color}{color:#ff}){color}
> {color:#ff} at 
> org.apache.cayenne.access.DataDomainQueryAction.execute({color}{color:#0066cc}DataDomainQueryAction.java:135{color}{color:#ff}){color}
> {color:#ff} at 
> org.apache.cayenne.access.DataDomain.onQueryNoFilters({color}{color:#0066cc}DataDomain.java:570{color}{color:#ff}){color}
> {color:#ff} at 
> org.apache.cayenne.access.DataDomain$DataDomainQueryFilterChain.onQuery({color}{color:#0066cc}DataDomain.java:819{color}{color:#ff}){color}
> {color:#ff} at 
> org.apache.cayenne.access.DataDomain.onQuery({color}{color:#0066cc}DataDomain.java:562{color}{color:#ff}){color}
> {color:#ff} at 
> org.apache.cayenne.util.ObjectContextQueryAction.runQuery({color}{color:#0066cc}ObjectContextQueryAction.java:406{color}{color:#ff}){color}
> {color:#ff} at 
> org.apache.cayenne.util.ObjectContextQueryAction.executePostCache({color}{color:#0066cc}ObjectContextQueryAction.java:107{color}{color:#ff}){color}
> {color:#ff} at 
> org.apache.cayenne.util.ObjectContextQueryAction.execute({color}{color:#0066cc}ObjectContextQueryAction.java:94{color}{color:#ff}){color}
> {color:#ff} at 
> org.apache.cayenne.access.DataContext.onQuery({color}{color:#0066cc}DataContext.java:960{color}{color:#ff}){color}
> {color:#ff} at 
> org.apache.cayenne.access.DataContext.performQuery({color}{color:#0066cc}DataContext.java:949{color}{color:#ff}){color}
> {color:#ff} at 
> org.apache.cayenne.BaseContext.select({color}{color:#0066cc}BaseContext.java:307{color}{color:#ff}){color}
> {color:#ff} at 
> org.apache.cayenne.query.FluentSelect.select({color}{color:#0066cc}FluentSelect.java:160{color}{color:#ff}){color}
>  
> Workaround:  Add 
> {color:#00}{color:#00}.suppressDistinct(){color}{color} to the query.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)


[jira] [Commented] (CAY-2847) Improve duplicate select column detection when using order by

2024-02-29 Thread Jurgen Doll (Jira)


[ 
https://issues.apache.org/jira/browse/CAY-2847?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel=17822152#comment-17822152
 ] 

Jurgen Doll commented on CAY-2847:
--

Created a [PR|https://github.com/apache/cayenne/pull/610]

> Improve duplicate select column detection when using order by
> -
>
> Key: CAY-2847
> URL: https://issues.apache.org/jira/browse/CAY-2847
> Project: Cayenne
>  Issue Type: Sub-task
>  Components: Core Library
>Reporter: Jurgen Doll
>Priority: Minor
>  Labels: pull-request-available
>  Time Spent: 10m
>  Remaining Estimate: 0h
>
> The current implementation has three problems:
>  # It fails when a column has an alias
>  # It builds the whole SQL column string before comparing
>  # It doesn't seem very robust in preventing false results
>  



--
This message was sent by Atlassian Jira
(v8.20.10#820010)


(cayenne) branch STABLE-4.2 updated: CAY-2838 Vertical Inheritance: Problem setting db attribute to null via flattened path

2024-02-29 Thread ntimofeev
This is an automated email from the ASF dual-hosted git repository.

ntimofeev pushed a commit to branch STABLE-4.2
in repository https://gitbox.apache.org/repos/asf/cayenne.git


The following commit(s) were added to refs/heads/STABLE-4.2 by this push:
 new c56c9fa87 CAY-2838 Vertical Inheritance: Problem setting db attribute 
to null via flattened path
c56c9fa87 is described below

commit c56c9fa870537bebd4623203707ac453203b59b5
Author: Nikita Timofeev 
AuthorDate: Thu Feb 29 17:08:19 2024 +0400

CAY-2838 Vertical Inheritance: Problem setting db attribute to null via 
flattened path
---
 .../cayenne/dba/sqlserver/SQLServerAdapter.java| 54 +-
 .../cayenne/access/VerticalInheritanceIT.java  | 29 +---
 2 files changed, 65 insertions(+), 18 deletions(-)

diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerAdapter.java
 
b/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerAdapter.java
index 0b71a2028..93efb47ea 100644
--- 
a/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerAdapter.java
+++ 
b/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerAdapter.java
@@ -20,8 +20,12 @@
 package org.apache.cayenne.dba.sqlserver;
 
 import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
 import java.util.List;
+import java.util.stream.Collectors;
 
+import org.apache.cayenne.CayenneRuntimeException;
 import org.apache.cayenne.access.DataNode;
 import org.apache.cayenne.access.sqlbuilder.sqltree.SQLTreeProcessor;
 import org.apache.cayenne.access.types.ExtendedType;
@@ -31,6 +35,8 @@ import org.apache.cayenne.configuration.Constants;
 import org.apache.cayenne.configuration.RuntimeProperties;
 import org.apache.cayenne.dba.sybase.SybaseAdapter;
 import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.map.DbAttribute;
+import org.apache.cayenne.map.DbEntity;
 import org.apache.cayenne.query.Query;
 import org.apache.cayenne.query.SQLAction;
 import org.apache.cayenne.resource.ResourceLocator;
@@ -114,7 +120,7 @@ public class SQLServerAdapter extends SybaseAdapter {
public boolean supportsGeneratedKeysForBatchInserts() {
return false;
}
-   
+
/**
 * @since 4.2
 */
@@ -157,4 +163,50 @@ public class SQLServerAdapter extends SybaseAdapter {
public void setVersion(Integer version) {
this.version = version;
}
+
+/**
+ * Generates DDL to create unique index that allows multiple NULL values 
to comply with ANSI SQL,
+ * that is default behaviour for other RDBMS.
+ * 
+ * Example:
+ * 
+ * {@code
+ * CREATE UNIQUE NONCLUSTERED INDEX _idx_entity_attribute
+ * ON entity(attribute)
+ * WHERE attribute IS NOT NULL
+ * }
+ * 
+ *
+ * @param source  entity for the index
+ * @param columns source columns for the index
+ * @return DDL to create unique index
+ *
+ * @since 4.2.1
+ */
+@Override
+public String createUniqueConstraint(DbEntity source, 
Collection columns) {
+if (columns == null || columns.isEmpty()) {
+throw new CayenneRuntimeException("Can't create UNIQUE constraint 
- no columns specified.");
+}
+
+return "CREATE UNIQUE NONCLUSTERED INDEX " + uniqueIndexName(source, 
columns) + " ON " +
+quotingStrategy.quotedFullyQualifiedName(source) +
+"(" +
+
columns.stream().map(quotingStrategy::quotedName).collect(Collectors.joining(", 
")) +
+") WHERE " +
+columns.stream().map(quotingStrategy::quotedName)
+.map(n -> n + " IS NOT NULL")
+.collect(Collectors.joining(" AND "));
+}
+
+private String uniqueIndexName(DbEntity source, Collection 
columns) {
+return "_idx_unique_"
++ source.getName().replace(' ', '_').toLowerCase()
++ "_"
++ columns.stream()
+.map(DbAttribute::getName)
+.map(String::toLowerCase)
+.map(n -> n.replace(' ', '_'))
+.collect(Collectors.joining("_"));
+}
 }
diff --git 
a/cayenne-server/src/test/java/org/apache/cayenne/access/VerticalInheritanceIT.java
 
b/cayenne-server/src/test/java/org/apache/cayenne/access/VerticalInheritanceIT.java
index eba76fb85..6f17d11c8 100644
--- 
a/cayenne-server/src/test/java/org/apache/cayenne/access/VerticalInheritanceIT.java
+++ 
b/cayenne-server/src/test/java/org/apache/cayenne/access/VerticalInheritanceIT.java
@@ -33,6 +33,7 @@ import org.apache.cayenne.testdo.inheritance_vertical.*;
 import org.apache.cayenne.unit.di.server.CayenneProjects;
 import org.apache.cayenne.unit.di.server.ServerCase;
 import org.apache.cayenne.unit.di.server.UseServerRuntime;
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -72,6 +73,15 

[PR] CAY-2847 Improve duplicate select column detection when using order by [cayenne]

2024-02-29 Thread via GitHub


Jugen opened a new pull request, #610:
URL: https://github.com/apache/cayenne/pull/610

   The current implementation has three problems:
   
   1. It fails when a column has an alias
   2. It builds the whole SQL column string before comparing
   3. It doesn't seem very robust in preventing false results
   
   This PR replaces the current implementation with a visitor pattern that 
fails fast.
   The visitor extracts each node's parts into a List which is progressively 
compared to the parts extracted from the order node.
   Each item must match in position and content in both lists for them to match 
and will abort comparing as soon as possible.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscr...@cayenne.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org



[jira] [Created] (CAY-2847) Improve duplicate select column detection when using order by

2024-02-29 Thread Jurgen Doll (Jira)
Jurgen Doll created CAY-2847:


 Summary: Improve duplicate select column detection when using 
order by
 Key: CAY-2847
 URL: https://issues.apache.org/jira/browse/CAY-2847
 Project: Cayenne
  Issue Type: Sub-task
  Components: Core Library
Reporter: Jurgen Doll


The current implementation has three problems:
 # It fails when a column has an alias
 # It builds the whole SQL column string before comparing
 # It doesn't seem very robust in preventing false results

 



--
This message was sent by Atlassian Jira
(v8.20.10#820010)


[jira] [Updated] (CAY-2842) Prevent duplicate select columns when using distinct with order by

2024-02-29 Thread Jurgen Doll (Jira)


 [ 
https://issues.apache.org/jira/browse/CAY-2842?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Jurgen Doll updated CAY-2842:
-
Fix Version/s: (was: 5.0-M2)

> Prevent duplicate select columns when using distinct with order by
> --
>
> Key: CAY-2842
> URL: https://issues.apache.org/jira/browse/CAY-2842
> Project: Cayenne
>  Issue Type: Improvement
>  Components: Core Library
>Affects Versions: 4.2
>Reporter: Jurgen Doll
>Priority: Minor
>  Labels: pull-request-available
>  Time Spent: 6h 50m
>  Remaining Estimate: 0h
>
> When a "select distinct" query has an "order by" clause then the "order by" 
> fields must also be listed in the select clause. However no check is 
> currently done to see if the column is already specified which can result in 
> duplicate columns being fetched.
> This is listed as a TODO item in OrderingStage.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)


Re: [PR] CAY-2842 Prevent duplicate select columns when using distinct with order by [cayenne]

2024-02-29 Thread via GitHub


stariy95 commented on code in PR #605:
URL: https://github.com/apache/cayenne/pull/605#discussion_r1507364687


##
cayenne/src/main/java/org/apache/cayenne/access/translator/select/OrderingAbstractStage.java:
##
@@ -0,0 +1,107 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *https://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ /
+
+package org.apache.cayenne.access.translator.select;
+
+import static org.apache.cayenne.access.sqlbuilder.SQLBuilder.*;
+
+import java.util.function.Predicate;
+
+import org.apache.cayenne.access.sqlbuilder.NodeBuilder;
+import org.apache.cayenne.access.sqlbuilder.SQLGenerationVisitor;
+import org.apache.cayenne.access.sqlbuilder.StringBuilderAppendable;
+import org.apache.cayenne.access.sqlbuilder.sqltree.ColumnNode;
+import org.apache.cayenne.access.sqlbuilder.sqltree.FunctionNode;
+import org.apache.cayenne.access.sqlbuilder.sqltree.Node;
+import org.apache.cayenne.access.sqlbuilder.sqltree.NodeType;
+import org.apache.cayenne.access.sqlbuilder.sqltree.SelectResultNode;
+import org.apache.cayenne.access.sqlbuilder.sqltree.SimpleNodeTreeVisitor;
+import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.exp.parser.ASTAggregateFunctionCall;
+import org.apache.cayenne.map.DbAttribute;
+import org.apache.cayenne.query.Ordering;
+
+abstract class OrderingAbstractStage implements TranslationStage {
+
+protected void processOrdering(QualifierTranslator qualifierTranslator, 
TranslatorContext context, Ordering ordering) {
+Expression orderExp = ordering.getSortSpec();
+NodeBuilder nodeBuilder = 
node(qualifierTranslator.translate(orderExp));
+
+if(ordering.isCaseInsensitive()) {
+nodeBuilder = function("UPPER", nodeBuilder);
+}
+
+// If query is DISTINCT or GROUPING then we need to add the order 
column as a result column
+if (orderColumnAbsent(context, nodeBuilder)) {
+// deepCopy as some DB expect exactly the same expression in 
select and in ordering
+ResultNodeDescriptor descriptor = 
context.addResultNode(nodeBuilder.build().deepCopy());
+if(orderExp instanceof ASTAggregateFunctionCall) {
+descriptor.setAggregate(true);
+}
+}
+}
+
+private DbAttribute getOrderDbAttribute(Node translatedOrderNode)
+{
+DbAttribute[] orderDbAttribute = {null};
+translatedOrderNode.visit(new SimpleNodeTreeVisitor() {
+@Override
+public boolean onNodeStart(Node node) {
+if (node.getType() == NodeType.COLUMN) {
+orderDbAttribute[0] = ((ColumnNode) node).getAttribute();
+return false;
+}
+return true;
+}
+});
+return orderDbAttribute[0];
+}
+
+private boolean orderColumnAbsent(TranslatorContext context, NodeBuilder 
nodeBuilder)
+{
+var orderDbAttribute = getOrderDbAttribute(nodeBuilder.build());
+if (orderDbAttribute == null) return false; // Alias ?
+
+var orderEntity = orderDbAttribute.getEntity().getName();
+var orderColumn = orderDbAttribute.getName();
+
+Predicate columnAndEntity = dba -> dba != null
+&& orderColumn.equals(dba.getName())
+&& 
orderEntity.equals(dba.getEntity().getName());
+
+var orderStr = getSqlString(order(nodeBuilder));
+
+return context.getResultNodeList().stream()
+.filter( result -> columnAndEntity.test(result.getDbAttribute()) )
+.noneMatch( result -> 
getSqlString(node(result.getNode())).startsWith(orderStr) );

Review Comment:
   @Jugen If it's more than a few lines of code, then it's better to open a new 
Jira issue.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscr...@cayenne.apache.org

For queries about this service, please contact Infrastructure at:

[jira] [Updated] (CAY-2842) Prevent duplicate select columns when using distinct with order by

2024-02-29 Thread Jurgen Doll (Jira)


 [ 
https://issues.apache.org/jira/browse/CAY-2842?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Jurgen Doll updated CAY-2842:
-
Fix Version/s: 5.0-M2

> Prevent duplicate select columns when using distinct with order by
> --
>
> Key: CAY-2842
> URL: https://issues.apache.org/jira/browse/CAY-2842
> Project: Cayenne
>  Issue Type: Improvement
>  Components: Core Library
>Affects Versions: 4.2
>Reporter: Jurgen Doll
>Priority: Minor
>  Labels: pull-request-available
> Fix For: 5.0-M2
>
>  Time Spent: 6h 40m
>  Remaining Estimate: 0h
>
> When a "select distinct" query has an "order by" clause then the "order by" 
> fields must also be listed in the select clause. However no check is 
> currently done to see if the column is already specified which can result in 
> duplicate columns being fetched.
> This is listed as a TODO item in OrderingStage.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)


Re: [PR] CAY-2842 Prevent duplicate select columns when using distinct with order by [cayenne]

2024-02-29 Thread via GitHub


Jugen commented on code in PR #605:
URL: https://github.com/apache/cayenne/pull/605#discussion_r1507359482


##
cayenne/src/main/java/org/apache/cayenne/access/translator/select/OrderingAbstractStage.java:
##
@@ -0,0 +1,107 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *https://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ /
+
+package org.apache.cayenne.access.translator.select;
+
+import static org.apache.cayenne.access.sqlbuilder.SQLBuilder.*;
+
+import java.util.function.Predicate;
+
+import org.apache.cayenne.access.sqlbuilder.NodeBuilder;
+import org.apache.cayenne.access.sqlbuilder.SQLGenerationVisitor;
+import org.apache.cayenne.access.sqlbuilder.StringBuilderAppendable;
+import org.apache.cayenne.access.sqlbuilder.sqltree.ColumnNode;
+import org.apache.cayenne.access.sqlbuilder.sqltree.FunctionNode;
+import org.apache.cayenne.access.sqlbuilder.sqltree.Node;
+import org.apache.cayenne.access.sqlbuilder.sqltree.NodeType;
+import org.apache.cayenne.access.sqlbuilder.sqltree.SelectResultNode;
+import org.apache.cayenne.access.sqlbuilder.sqltree.SimpleNodeTreeVisitor;
+import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.exp.parser.ASTAggregateFunctionCall;
+import org.apache.cayenne.map.DbAttribute;
+import org.apache.cayenne.query.Ordering;
+
+abstract class OrderingAbstractStage implements TranslationStage {
+
+protected void processOrdering(QualifierTranslator qualifierTranslator, 
TranslatorContext context, Ordering ordering) {
+Expression orderExp = ordering.getSortSpec();
+NodeBuilder nodeBuilder = 
node(qualifierTranslator.translate(orderExp));
+
+if(ordering.isCaseInsensitive()) {
+nodeBuilder = function("UPPER", nodeBuilder);
+}
+
+// If query is DISTINCT or GROUPING then we need to add the order 
column as a result column
+if (orderColumnAbsent(context, nodeBuilder)) {
+// deepCopy as some DB expect exactly the same expression in 
select and in ordering
+ResultNodeDescriptor descriptor = 
context.addResultNode(nodeBuilder.build().deepCopy());
+if(orderExp instanceof ASTAggregateFunctionCall) {
+descriptor.setAggregate(true);
+}
+}
+}
+
+private DbAttribute getOrderDbAttribute(Node translatedOrderNode)
+{
+DbAttribute[] orderDbAttribute = {null};
+translatedOrderNode.visit(new SimpleNodeTreeVisitor() {
+@Override
+public boolean onNodeStart(Node node) {
+if (node.getType() == NodeType.COLUMN) {
+orderDbAttribute[0] = ((ColumnNode) node).getAttribute();
+return false;
+}
+return true;
+}
+});
+return orderDbAttribute[0];
+}
+
+private boolean orderColumnAbsent(TranslatorContext context, NodeBuilder 
nodeBuilder)
+{
+var orderDbAttribute = getOrderDbAttribute(nodeBuilder.build());
+if (orderDbAttribute == null) return false; // Alias ?
+
+var orderEntity = orderDbAttribute.getEntity().getName();
+var orderColumn = orderDbAttribute.getName();
+
+Predicate columnAndEntity = dba -> dba != null
+&& orderColumn.equals(dba.getName())
+&& 
orderEntity.equals(dba.getEntity().getName());
+
+var orderStr = getSqlString(order(nodeBuilder));
+
+return context.getResultNodeList().stream()
+.filter( result -> columnAndEntity.test(result.getDbAttribute()) )
+.noneMatch( result -> 
getSqlString(node(result.getNode())).startsWith(orderStr) );

Review Comment:
   @stariy95 I'm ready to submit a new PR for the Node.visit pattern but need 
some guidance on how to go about it ?
   Should I create a new Jira RFE issue and submit against that, or just do an 
ordinary PR ?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: 

(cayenne) branch STABLE-4.2 updated: CAY-2838 Vertical Inheritance: Problem setting db attribute to null via flattened path

2024-02-29 Thread ntimofeev
This is an automated email from the ASF dual-hosted git repository.

ntimofeev pushed a commit to branch STABLE-4.2
in repository https://gitbox.apache.org/repos/asf/cayenne.git


The following commit(s) were added to refs/heads/STABLE-4.2 by this push:
 new 394f63c61 CAY-2838 Vertical Inheritance: Problem setting db attribute 
to null via flattened path
394f63c61 is described below

commit 394f63c61de003af581911bd1b61816f7a12a5b7
Author: Nikita Timofeev 
AuthorDate: Thu Feb 29 13:57:26 2024 +0400

CAY-2838 Vertical Inheritance: Problem setting db attribute to null via 
flattened path
---
 .../cayenne/access/VerticalInheritanceIT.java  | 54 ++
 1 file changed, 24 insertions(+), 30 deletions(-)

diff --git 
a/cayenne-server/src/test/java/org/apache/cayenne/access/VerticalInheritanceIT.java
 
b/cayenne-server/src/test/java/org/apache/cayenne/access/VerticalInheritanceIT.java
index 7103b7fee..eba76fb85 100644
--- 
a/cayenne-server/src/test/java/org/apache/cayenne/access/VerticalInheritanceIT.java
+++ 
b/cayenne-server/src/test/java/org/apache/cayenne/access/VerticalInheritanceIT.java
@@ -33,6 +33,7 @@ import org.apache.cayenne.testdo.inheritance_vertical.*;
 import org.apache.cayenne.unit.di.server.CayenneProjects;
 import org.apache.cayenne.unit.di.server.ServerCase;
 import org.apache.cayenne.unit.di.server.UseServerRuntime;
+import org.junit.Before;
 import org.junit.Test;
 
 import java.sql.SQLException;
@@ -57,6 +58,20 @@ public class VerticalInheritanceIT extends ServerCase {
@Inject
protected ServerRuntime runtime;
 
+   TableHelper ivAbstractTable;
+
+   TableHelper ivConcreteTable;
+
+   @Before
+   public void setup() {
+   ivAbstractTable = new TableHelper(dbHelper, "IV_ABSTRACT");
+   ivAbstractTable.setColumns("ID", "PARENT_ID", "TYPE")
+   .setColumnTypes(Types.INTEGER, Types.INTEGER, 
Types.CHAR);
+   ivConcreteTable = new TableHelper(dbHelper, "IV_CONCRETE");
+   ivConcreteTable.setColumns("ID", "NAME", "RELATED_ABSTRACT_ID")
+   .setColumnTypes(Types.INTEGER, Types.VARCHAR, 
Types.INTEGER);
+   }
+
 @Test
public void testInsert_Root() throws Exception {
 
@@ -595,7 +610,7 @@ public class VerticalInheritanceIT extends ServerCase {
}
 
@Test
-   public void testUpdateWithRelationship() {
+   public void testUpdateWithRelationship() throws SQLException {
IvConcrete parent1 = context.newObject(IvConcrete.class);
parent1.setName("Parent1");
context.commitChanges();
@@ -615,15 +630,15 @@ public class VerticalInheritanceIT extends ServerCase {
assertEquals(parent2, child.getParent());
 
// Manually delete child to prevent a foreign key constraint 
failure while cleaning MySQL db
-   context.deleteObject(child);
-   context.commitChanges();
+   ivConcreteTable.deleteAll();
+   ivAbstractTable.deleteAll();
}
 
/**
  * @link https://issues.apache.org/jira/browse/CAY-2838
  */
@Test
-   public void testNullifyFlattenedAttribute() {
+   public void testNullifyFlattenedAttribute() throws SQLException {
IvConcrete concrete = context.newObject(IvConcrete.class);
concrete.setName("Concrete");
context.commitChanges();
@@ -639,6 +654,9 @@ public class VerticalInheritanceIT extends ServerCase {
IvConcrete concreteFetched = 
SelectById.query(IvConcrete.class, id).selectOne(cleanContext);
assertNull(concreteFetched.getName());
}
+
+   ivConcreteTable.deleteAll();
+   ivAbstractTable.deleteAll();
}
 
@Test
@@ -667,14 +685,6 @@ public class VerticalInheritanceIT extends ServerCase {
 
@Test
public void testDeleteFlattenedNoValues() throws SQLException {
-   TableHelper ivAbstractTable = new TableHelper(dbHelper, 
"IV_ABSTRACT");
-   ivAbstractTable.setColumns("ID", "PARENT_ID", "TYPE")
-   .setColumnTypes(Types.INTEGER, Types.INTEGER, 
Types.CHAR);
-
-   TableHelper ivConcreteTable = new TableHelper(dbHelper, 
"IV_CONCRETE");
-   ivConcreteTable.setColumns("ID", "NAME")
-   .setColumnTypes(Types.INTEGER, Types.VARCHAR);
-
ivAbstractTable.insert(1, null, "S");
 
IvConcrete concrete = SelectById.query(IvConcrete.class, 
1).selectOne(context);
@@ -690,16 +700,8 @@ public class VerticalInheritanceIT extends ServerCase {
 
@Test
public void testDeleteFlattenedNullValues() throws SQLException {
-   TableHelper ivAbstractTable = new TableHelper(dbHelper, 
"IV_ABSTRACT");
-   ivAbstractTable.setColumns("ID", 

(cayenne) branch STABLE-4.2 updated: CAY-2838 Vertical Inheritance: Problem setting db attribute to null via flattened path

2024-02-29 Thread ntimofeev
This is an automated email from the ASF dual-hosted git repository.

ntimofeev pushed a commit to branch STABLE-4.2
in repository https://gitbox.apache.org/repos/asf/cayenne.git


The following commit(s) were added to refs/heads/STABLE-4.2 by this push:
 new e882c10d8 CAY-2838 Vertical Inheritance: Problem setting db attribute 
to null via flattened path
e882c10d8 is described below

commit e882c10d8101537724eb0e765a0d32a296ec7047
Author: Nikita Timofeev 
AuthorDate: Thu Feb 29 13:47:16 2024 +0400

CAY-2838 Vertical Inheritance: Problem setting db attribute to null via 
flattened path
---
 .../test/java/org/apache/cayenne/access/VerticalInheritanceIT.java| 4 
 1 file changed, 4 insertions(+)

diff --git 
a/cayenne-server/src/test/java/org/apache/cayenne/access/VerticalInheritanceIT.java
 
b/cayenne-server/src/test/java/org/apache/cayenne/access/VerticalInheritanceIT.java
index 4f9a33196..7103b7fee 100644
--- 
a/cayenne-server/src/test/java/org/apache/cayenne/access/VerticalInheritanceIT.java
+++ 
b/cayenne-server/src/test/java/org/apache/cayenne/access/VerticalInheritanceIT.java
@@ -770,6 +770,10 @@ public class VerticalInheritanceIT extends ServerCase {
assertEquals("Two", concreteFetched.getName());
assertNull(concreteFetched.getRelatedAbstract());
}
+
+   // must clean these tables manually
+   ivConcreteTable.deleteAll();
+   ivAbstractTable.deleteAll();
}
 
@Test//(expected = ValidationException.class) // other2 is not 
mandatory for now



(cayenne) 02/02: CAY-2838 Vertical Inheritance: Problem setting db attribute to null via flattened path

2024-02-29 Thread ntimofeev
This is an automated email from the ASF dual-hosted git repository.

ntimofeev pushed a commit to branch STABLE-4.2
in repository https://gitbox.apache.org/repos/asf/cayenne.git

commit cc51de1baecc1e67e08206a9603d8618cb91aecd
Author: Nikita Timofeev 
AuthorDate: Thu Feb 29 13:08:16 2024 +0400

CAY-2838 Vertical Inheritance: Problem setting db attribute to null via 
flattened path
---
 .../access/flush/ArcValuesCreationHandler.java| 19 ---
 1 file changed, 16 insertions(+), 3 deletions(-)

diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/access/flush/ArcValuesCreationHandler.java
 
b/cayenne-server/src/main/java/org/apache/cayenne/access/flush/ArcValuesCreationHandler.java
index 1ca012aa6..560ab7bfa 100644
--- 
a/cayenne-server/src/main/java/org/apache/cayenne/access/flush/ArcValuesCreationHandler.java
+++ 
b/cayenne-server/src/main/java/org/apache/cayenne/access/flush/ArcValuesCreationHandler.java
@@ -119,7 +119,7 @@ class ArcValuesCreationHandler implements 
GraphChangeHandler {
 // if ID is present, just use it, otherwise create new
 String flattenedPath = path.toString();
 
-// if this is last segment and it's a relationship, use known 
target id from arc creation
+// if this is the last segment, and it's a relationship, use 
known target id from arc creation
 if(!dbPathIterator.hasNext()) {
 targetId = finalTargetId;
 } else {
@@ -151,8 +151,7 @@ class ArcValuesCreationHandler implements 
GraphChangeHandler {
 // should update existing DB row
 factory.getOrCreate(target, targetId, add ? 
DbRowOpType.UPDATE : defaultType);
 }
-// should always add data from the intermediate relationship
-processRelationship(relationship, srcId, targetId, 
dbPathIterator.hasNext() || add);
+processRelationship(relationship, srcId, targetId, 
shouldProcessAsAddition(relationship, add));
 srcId = targetId; // use target as next source
 }
 }
@@ -160,6 +159,20 @@ class ArcValuesCreationHandler implements 
GraphChangeHandler {
 return targetId;
 }
 
+private boolean shouldProcessAsAddition(DbRelationship relationship, 
boolean add) {
+if(add) {
+return true;
+}
+
+// should always add data from one-to-one relationships
+for(DbJoin join : relationship.getJoins()) {
+if(!join.getSource().isPrimaryKey() || 
!join.getTarget().isPrimaryKey()) {
+return false;
+}
+}
+return true;
+}
+
 protected void processRelationship(DbRelationship dbRelationship, ObjectId 
srcId, ObjectId targetId, boolean add) {
 for(DbJoin join : dbRelationship.getJoins()) {
 boolean srcPK = join.getSource().isPrimaryKey();



(cayenne) branch STABLE-4.2 updated (c987980c7 -> cc51de1ba)

2024-02-29 Thread ntimofeev
This is an automated email from the ASF dual-hosted git repository.

ntimofeev pushed a change to branch STABLE-4.2
in repository https://gitbox.apache.org/repos/asf/cayenne.git


from c987980c7 CAY-2841 Multi column ColumnSelect with SHARED_CACHE fails 
after 1st select
 new ca6f9d944 CAY-2838 Vertical Inheritance: Problem setting db attribute 
to null via flattened path
 new cc51de1ba CAY-2838 Vertical Inheritance: Problem setting db attribute 
to null via flattened path

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../access/flush/ArcValuesCreationHandler.java | 19 +++---
 .../cayenne/access/VerticalInheritanceIT.java  | 29 ++
 .../inheritance_vertical/auto/_IvAbstract.java | 19 ++
 .../inheritance_vertical/auto/_IvConcrete.java | 17 +
 .../test/resources/inheritance-vertical.map.xml|  9 +++
 5 files changed, 90 insertions(+), 3 deletions(-)



(cayenne) 01/02: CAY-2838 Vertical Inheritance: Problem setting db attribute to null via flattened path

2024-02-29 Thread ntimofeev
This is an automated email from the ASF dual-hosted git repository.

ntimofeev pushed a commit to branch STABLE-4.2
in repository https://gitbox.apache.org/repos/asf/cayenne.git

commit ca6f9d944d2995e4ab76728695c0cd9097170c4a
Author: Jadon Hansell <130694311+jghans...@users.noreply.github.com>
AuthorDate: Thu Feb 29 13:08:11 2024 +0400

CAY-2838 Vertical Inheritance: Problem setting db attribute to null via 
flattened path
---
 .../cayenne/access/VerticalInheritanceIT.java  | 29 ++
 .../inheritance_vertical/auto/_IvAbstract.java | 19 ++
 .../inheritance_vertical/auto/_IvConcrete.java | 17 +
 .../test/resources/inheritance-vertical.map.xml|  9 +++
 4 files changed, 74 insertions(+)

diff --git 
a/cayenne-server/src/test/java/org/apache/cayenne/access/VerticalInheritanceIT.java
 
b/cayenne-server/src/test/java/org/apache/cayenne/access/VerticalInheritanceIT.java
index e826fa112..4f9a33196 100644
--- 
a/cayenne-server/src/test/java/org/apache/cayenne/access/VerticalInheritanceIT.java
+++ 
b/cayenne-server/src/test/java/org/apache/cayenne/access/VerticalInheritanceIT.java
@@ -743,6 +743,35 @@ public class VerticalInheritanceIT extends ServerCase {
assertEquals(0, ivConcreteTable.getRowCount());
}
 
+   @Test
+   public void testNullifyFlattenedRelationshipConcreteToAbstract() throws 
SQLException {
+   TableHelper ivAbstractTable = new TableHelper(dbHelper, 
"IV_ABSTRACT");
+   ivAbstractTable.setColumns("ID", "PARENT_ID", "TYPE")
+   .setColumnTypes(Types.INTEGER, Types.INTEGER, 
Types.CHAR);
+
+   TableHelper ivConcreteTable = new TableHelper(dbHelper, 
"IV_CONCRETE");
+   ivConcreteTable.setColumns("ID", "NAME", "RELATED_ABSTRACT_ID")
+   .setColumnTypes(Types.INTEGER, Types.VARCHAR, 
Types.INTEGER);
+
+   ivAbstractTable.insert(1, null, "S");
+   ivConcreteTable.insert(1, "One", null);
+   ivAbstractTable.insert(2, null, "S");
+   ivConcreteTable.insert(2, "Two", 1);
+
+   IvConcrete concrete = SelectById.query(IvConcrete.class, 
2).selectOne(context);
+   concrete.setRelatedAbstract(null);
+
+   context.commitChanges();
+   assertNull(concrete.getRelatedAbstract());
+
+   {
+   ObjectContext cleanContext = runtime.newContext();
+   IvConcrete concreteFetched = 
SelectById.query(IvConcrete.class, 2).selectOne(cleanContext);
+   assertEquals("Two", concreteFetched.getName());
+   assertNull(concreteFetched.getRelatedAbstract());
+   }
+   }
+
@Test//(expected = ValidationException.class) // other2 is not 
mandatory for now
public void testInsertWithAttributeAndRelationship() {
IvOther other = context.newObject(IvOther.class);
diff --git 
a/cayenne-server/src/test/java/org/apache/cayenne/testdo/inheritance_vertical/auto/_IvAbstract.java
 
b/cayenne-server/src/test/java/org/apache/cayenne/testdo/inheritance_vertical/auto/_IvAbstract.java
index 48d19280c..e8669b2e4 100644
--- 
a/cayenne-server/src/test/java/org/apache/cayenne/testdo/inheritance_vertical/auto/_IvAbstract.java
+++ 
b/cayenne-server/src/test/java/org/apache/cayenne/testdo/inheritance_vertical/auto/_IvAbstract.java
@@ -5,8 +5,10 @@ import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
 
 import org.apache.cayenne.BaseDataObject;
+import org.apache.cayenne.exp.property.EntityProperty;
 import org.apache.cayenne.exp.property.PropertyFactory;
 import org.apache.cayenne.exp.property.StringProperty;
+import org.apache.cayenne.testdo.inheritance_vertical.IvConcrete;
 
 /**
  * Class _IvAbstract was generated by Cayenne.
@@ -21,9 +23,11 @@ public abstract class _IvAbstract extends BaseDataObject {
 public static final String ID_PK_COLUMN = "ID";
 
 public static final StringProperty TYPE = 
PropertyFactory.createString("type", String.class);
+public static final EntityProperty RELATED_CONCRETE = 
PropertyFactory.createEntity("relatedConcrete", IvConcrete.class);
 
 protected String type;
 
+protected Object relatedConcrete;
 
 public void setType(String type) {
 beforePropertyWrite("type", this.type, type);
@@ -35,6 +39,14 @@ public abstract class _IvAbstract extends BaseDataObject {
 return this.type;
 }
 
+public void setRelatedConcrete(IvConcrete relatedConcrete) {
+setToOneTarget("relatedConcrete", relatedConcrete, true);
+}
+
+public IvConcrete getRelatedConcrete() {
+return (IvConcrete)readProperty("relatedConcrete");
+}
+
 @Override
 public Object readPropertyDirectly(String propName) {
 if(propName == null) {
@@ -44,6 +56,8 @@ public abstract class _IvAbstract extends BaseDataObject {