Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright (c) 1998, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
// Contributors:
// Oracle - initial API and implementation from Oracle TopLink
// 11/10/2011-2.4 Guy Pelletier
// - 357474: Address primaryKey option from tenant discriminator column
package org.eclipse.persistence.internal.expressions;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.descriptors.FetchGroupManager;
import org.eclipse.persistence.exceptions.QueryException;
import org.eclipse.persistence.expressions.Expression;
import org.eclipse.persistence.internal.helper.DatabaseField;
import org.eclipse.persistence.internal.helper.DatabaseTable;
import org.eclipse.persistence.internal.identitymaps.CacheId;
import org.eclipse.persistence.internal.queries.MappedKeyMapContainerPolicy;
import org.eclipse.persistence.internal.sessions.AbstractRecord;
import org.eclipse.persistence.internal.sessions.AbstractSession;
import org.eclipse.persistence.internal.sessions.UnitOfWorkImpl;
import org.eclipse.persistence.mappings.AggregateObjectMapping;
import org.eclipse.persistence.mappings.CollectionMapping;
import org.eclipse.persistence.mappings.DatabaseMapping;
import org.eclipse.persistence.mappings.DirectCollectionMapping;
import org.eclipse.persistence.mappings.ForeignReferenceMapping;
import org.eclipse.persistence.mappings.ManyToManyMapping;
import org.eclipse.persistence.mappings.ObjectReferenceMapping;
import org.eclipse.persistence.mappings.OneToOneMapping;
import org.eclipse.persistence.mappings.foundation.AbstractColumnMapping;
import org.eclipse.persistence.mappings.querykeys.DirectQueryKey;
import org.eclipse.persistence.mappings.querykeys.ForeignReferenceQueryKey;
import org.eclipse.persistence.mappings.querykeys.QueryKey;
import org.eclipse.persistence.queries.DatabaseQuery;
import org.eclipse.persistence.queries.InMemoryQueryIndirectionPolicy;
import org.eclipse.persistence.queries.ReadQuery;
import java.io.BufferedWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* Represents expression on query keys or mappings.
* This includes direct, relationships query keys and mappings.
*/
public class QueryKeyExpression extends ObjectExpression {
/** The name of the query key. */
protected String name;
/** Cache the aliased field. Only applies to attributes. */
protected DatabaseField aliasedField;
/** Is this a query across a 1:many or many:many relationship. Does not apply to attributes. */
protected boolean shouldQueryToManyRelationship;
/** Cache the query key for performance. Store a boolean so we don't repeat the search if there isn't one. */
transient protected QueryKey queryKey;
protected boolean hasQueryKey;
/** Cache the mapping for performance. Store a boolean so we don't repeat the search if there isn't one. */
transient protected DatabaseMapping mapping;
protected boolean hasMapping;
/** PERF: Cache if the expression is an attribute expression. */
protected Boolean isAttributeExpression;
protected IndexExpression index;
protected boolean isClonedForSubQuery = false;
public QueryKeyExpression() {
this.shouldQueryToManyRelationship = false;
this.hasQueryKey = true;
this.hasMapping = true;
}
public QueryKeyExpression(String aName, Expression base) {
super();
name = aName;
baseExpression = base;
shouldUseOuterJoin = false;
shouldQueryToManyRelationship = false;
hasQueryKey = true;
hasMapping = true;
}
/**
* INTERNAL:
* Return if the expression is equal to the other.
* This is used to allow dynamic expression's SQL to be cached.
*/
@Override
public boolean equals(Object object) {
if (this == object) {
return true;
}
if (!super.equals(object)) {
return false;
}
QueryKeyExpression expression = (QueryKeyExpression) object;
// Return false for anyOf expressions, as equality is unknown.
if (shouldQueryToManyRelationship() || expression.shouldQueryToManyRelationship()) {
return false;
}
return ((getName() == expression.getName()) || ((getName() != null) && getName().equals(expression.getName())));
}
/**
* INTERNAL:
* Compute a consistent hash-code for the expression.
* This is used to allow dynamic expression's SQL to be cached.
*/
@Override
public int computeHashCode() {
int hashCode = super.computeHashCode();
if (getName() != null) {
hashCode = hashCode + getName().hashCode();
}
return hashCode;
}
/**
* INTERNAL:
* Return the expression to join the main table of this node to any auxiliary tables.
*/
@Override
public Expression additionalExpressionCriteria() {
if (getDescriptor() == null) {
return null;
}
Expression criteria = getDescriptor().getQueryManager().getAdditionalJoinExpression();
if (criteria != null) {
criteria = this.baseExpression.twist(criteria, this);
if (shouldUseOuterJoin() && getSession().getPlatform().shouldPrintOuterJoinInWhereClause()) {
criteria.convertToUseOuterJoin();
}
}
if(getSession().getPlatform().shouldPrintOuterJoinInWhereClause()) {
if(isUsingOuterJoinForMultitableInheritance()) {
Expression childrenCriteria = getDescriptor().getInheritancePolicy().getChildrenJoinExpression();
childrenCriteria = this.baseExpression.twist(childrenCriteria, this);
childrenCriteria.convertToUseOuterJoin();
if(criteria == null) {
criteria = childrenCriteria;
} else {
criteria = criteria.and(childrenCriteria);
}
}
}
if (getDescriptor().getHistoryPolicy() != null) {
Expression historyCriteria = getDescriptor().getHistoryPolicy().additionalHistoryExpression(this, this);
if (criteria != null) {
criteria = criteria.and(historyCriteria);
} else {
criteria = historyCriteria;
}
}
return criteria;
}
/**
* INTERNAL:
* Used in case outer joins should be printed in FROM clause.
* Each of the additional tables mapped to expressions that joins it.
*/
@Override
public Map additionalExpressionCriteriaMap() {
if (getDescriptor() == null) {
return null;
}
Map tablesJoinExpressions = new HashMap<>();
List tables = getDescriptor().getTables();
// skip the main table - start with i=1
int tablesSize = tables.size();
if (shouldUseOuterJoin() || (!getSession().getPlatform().shouldPrintInnerJoinInWhereClause(getDescriptor().getQueryManager().getReadAllQuery()))) {
for (int i=1; i < tablesSize; i++) {
DatabaseTable table = tables.get(i);
Expression joinExpression = getDescriptor().getQueryManager().getTablesJoinExpressions().get(table);
joinExpression = this.baseExpression.twist(joinExpression, this);
if (getDescriptor().getHistoryPolicy() != null) {
joinExpression = joinExpression.and(getDescriptor().getHistoryPolicy().additionalHistoryExpression(this, this, i));
}
tablesJoinExpressions.put(table, joinExpression);
}
}
if (isUsingOuterJoinForMultitableInheritance()) {
List childrenTables = getDescriptor().getInheritancePolicy().getChildrenTables();
tablesSize = childrenTables.size();
for (int i=0; i < tablesSize; i++) {
DatabaseTable table = childrenTables.get(i);
Expression joinExpression = getDescriptor().getInheritancePolicy().getChildrenTablesJoinExpressions().get(table);
joinExpression = this.baseExpression.twist(joinExpression, this);
tablesJoinExpressions.put(table, joinExpression);
}
}
return tablesJoinExpressions;
}
/**
* INTERNAL:
* Find the alias for a given table
*/
@Override
public DatabaseTable aliasForTable(DatabaseTable table) {
DatabaseMapping mapping = getMapping();
if (isAttribute() || ((mapping != null) && (mapping.isAggregateObjectMapping() || mapping.isTransformationMapping()))) {
return this.baseExpression.aliasForTable(table);
}
//"ref" and "structure" mappings, no table printed in the FROM clause, need to get the table alias form the parent table
if ((mapping != null) && (mapping.isReferenceMapping() || mapping.isStructureMapping())) {
DatabaseTable alias = this.baseExpression.aliasForTable(mapping.getDescriptor().getTables().get(0));
alias.setName(alias.getName() + "." + mapping.getField().getName());
return alias;
}
// For direct-collection mappings the alias is store on the table expression.
if ((mapping != null) && (mapping.isDirectCollectionMapping())) {
if (tableAliases != null){
DatabaseTable aliasedTable = tableAliases.keyAtValue(table);
if (aliasedTable != null){
return aliasedTable;
}
}
return getTable(table).aliasForTable(table);
}
return super.aliasForTable(table);
}
/**
* ADVANCED:
* Return an expression that allows you to treat its base as if it were a subclass of the class returned by the base
* This can only be called on an ExpressionBuilder, the result of expression.get(String), expression.getAllowingNull(String),
* the result of expression.anyOf("String") or the result of expression.anyOfAllowingNull("String")
*
* downcast uses Expression.type() internally to guarantee the results are of the specified class.
*
*/
@Override
public Expression treat(Class> castClass){
//to be used in 'where treat(t as PerformanceTireInfo).speedRating > 100'
QueryKeyExpression clonedExpression = new TreatAsExpression(castClass, this);
clonedExpression.shouldQueryToManyRelationship = this.shouldQueryToManyRelationship;
//using shouldUseOuterJoin to indicate the join to use between the t and PerformanceTireInfo subclass.
clonedExpression.hasQueryKey = this.hasQueryKey;
clonedExpression.hasMapping = this.hasMapping;
this.addDerivedExpression(clonedExpression);
return clonedExpression;
}
/**
* INTERNAL:
* Used for cloning.
*/
@Override
protected void postCopyIn(Map alreadyDone) {
super.postCopyIn(alreadyDone);
if (this.index != null) {
this.index = (IndexExpression)this.index.copiedVersionFrom(alreadyDone);
}
}
/**
* INTERNAL:
* Used for debug printing.
*/
@Override
public String descriptionOfNodeType() {
return "Query Key";
}
/**
* INTERNAL:
*/
public void doQueryToManyRelationship() {
shouldQueryToManyRelationship = true;
}
/**
* INTERNAL:
* Return any additional tables that belong to this expression
* An example of how this method is used is to return any tables that belong to the map key
* when this expression traverses a mapping that uses a Map
*/
@Override
public List getAdditionalTables() {
if (mapping != null && mapping.isCollectionMapping()){
return mapping.getContainerPolicy().getAdditionalTablesForJoinQuery();
}
return null;
}
/**
* INTERNAL:
* Return the field appropriately aliased
*/
@Override
public DatabaseField getAliasedField() {
if (aliasedField == null) {
initializeAliasedField();
}
return aliasedField;
}
/**
* Return the alias for our table
*/
protected DatabaseTable getAliasedTable() {
DataExpression base = (DataExpression)this.baseExpression;
DatabaseTable alias = base.aliasForTable(getField().getTable());
if (alias == null) {
return getField().getTable();
} else {
return alias;
}
}
/**
* INTERNAL:
*/
@Override
public DatabaseField getField() {
if (!isAttribute()) {
return null;
}
QueryKey key = getQueryKeyOrNull();
if ((key != null) && key.isDirectQueryKey()) {
return ((DirectQueryKey)key).getField();
}
DatabaseMapping mapping = getMapping();
if ((mapping == null) || mapping.getFields().isEmpty()) {
return null;
}
return mapping.getFields().get(0);
}
/**
* INTERNAL:
* Return all the fields
*/
@Override
public List getFields() {
if (isAttribute()) {
List result = new ArrayList<>(1);
DatabaseField field = getField();
if (field != null) {
result.add(field);
}
return result;
} else {
List result = new ArrayList<>();
result.addAll(super.getFields());
if ((this.mapping != null) && this.mapping.isCollectionMapping()){
List fields = this.mapping.getContainerPolicy().getAdditionalFieldsForJoin((CollectionMapping)this.mapping);
if (fields != null){
result.addAll(fields);
}
}
return result;
}
}
/**
* INTERNAL:
*/
@Override
public List getSelectionFields(ReadQuery query) {
if (isAttribute()) {
List result = new ArrayList<>(1);
DatabaseField field = getField();
if (field != null) {
result.add(field);
}
return result;
} else {
List result = new ArrayList<>();
result.addAll(super.getSelectionFields(query));
if ((this.mapping != null) && this.mapping.isCollectionMapping()){
List fields = this.mapping.getContainerPolicy().getAdditionalFieldsForJoin((CollectionMapping)this.mapping);
if (fields != null){
result.addAll(fields);
}
}
return result;
}
}
/**
* INTERNAL:
* Transform the object-level value into a database-level value
*/
@Override
public Object getFieldValue(Object objectValue, AbstractSession session) {
DatabaseMapping mapping = getMapping();
Object fieldValue = objectValue;
if (mapping != null) {
if (mapping.isAbstractDirectMapping() || mapping.isDirectCollectionMapping()) {
// CR#3623207, check for IN Collection here not in mapping.
if (objectValue instanceof Collection> values) {
// This can actually be a collection for IN within expressions... however it would be better for expressions to handle this.
List