![JAR search and dependency download from the Maven repository](/logo.png)
com.gs.fw.common.mithra.finder.SqlQuery Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of reladomo Show documentation
Show all versions of reladomo Show documentation
Reladomo is an object-relational mapping framework.
/*
Copyright 2016 Goldman Sachs.
Licensed 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
http://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 com.gs.fw.common.mithra.finder;
import com.gs.collections.impl.list.mutable.FastList;
import com.gs.collections.impl.map.mutable.UnifiedMap;
import com.gs.collections.impl.set.mutable.UnifiedSet;
import com.gs.fw.common.mithra.MithraBusinessException;
import com.gs.fw.common.mithra.MithraObjectPortal;
import com.gs.fw.common.mithra.attribute.Attribute;
import com.gs.fw.common.mithra.attribute.TemporalAttribute;
import com.gs.fw.common.mithra.databasetype.DatabaseType;
import com.gs.fw.common.mithra.finder.asofop.AsOfOperation;
import com.gs.fw.common.mithra.finder.orderby.OrderBy;
import com.gs.fw.common.mithra.notification.MithraDatabaseIdentifierExtractor;
import com.gs.fw.common.mithra.tempobject.TupleTempContext;
import com.gs.fw.common.mithra.util.InternalList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
public class SqlQuery implements MapperStack, WhereClause.WhereClauseOwner
{
private static final Logger logger = LoggerFactory.getLogger(SqlQuery.class);
public static final String DEFAULT_DATABASE_ALIAS = MithraDatabaseIdentifierExtractor.DEFAULT_DATABASE_ALIAS;
private static final int CHARS_PER_TABLE_NAME = 20;
private WhereClause whereClause = new WhereClause(this);
private StringBuilder orderByClause = null;
// private InternalList sqlParameterSetters = new InternalList(3);
private InternalList setOperationWhereClausePositionList;
private SetBasedOpAndPosition largeInClause;
private MithraDatabaseIdentifierExtractor idExtractor = new MithraDatabaseIdentifierExtractor();
private AnalyzedOperation analyzedOperation;
private OrderBy orderby;
private int clauseCount;
private int totalInClauseParameters = 0;
private int numberOfChunksPerIn = 0;
private int numberOfUnions = 1;
private int numberOfQueries = 0;
private String firstWhereClause;
private String lastWhereClause;
private int currentUnionNumber = 0;
private boolean useDatabaseAliasInSqlQuery = true;
private List asOfAttributeWithMapperStackList;
private boolean forceServerSideOrderBy = false;
private DatabaseType databaseType;
private boolean preparedOnce = false;
private int currentSourceNumber;
private int maxUnionCount = -1;
private int tempTableNumber = 0;
private TimeZone timeZone = null;
private int currentQueryNumber;
private int finalUnionNumber = 1;
private boolean notExists = false;
private boolean disableTempTableJoin;
private InternalList tupleTempContextList;
private UnifiedSet subSelectedInClauses;
private String extraSelectColumns;
private boolean isParallel = false;
private UnifiedMap derivedColumnSubstitutionMap;
public SqlQuery(Operation op, OrderBy orderBy, boolean forceImplicitJoin)
{
this(new AnalyzedOperation(op), orderBy, forceImplicitJoin);
}
public SqlQuery(AnalyzedOperation analyzedOperation, OrderBy orderby, boolean forceExplicitJoin)
{
this.analyzedOperation = analyzedOperation;
this.orderby = orderby;
this.idExtractor.setUseExplicitJoins(!forceExplicitJoin && !analyzedOperation.getOriginalOperation().zHazTriangleJoins());
this.idExtractor.registerOperations(this.analyzedOperation.getAnalyzedOperation());
this.idExtractor.computeJoinClauseAggregation();
if (orderby != null)
{
orderby.registerSourceOperation(this.idExtractor);
}
}
protected MithraDatabaseIdentifierExtractor getCurrentIdExtractor()
{
return this.idExtractor;
}
public void prepareForQuery(int currentQueryNumber) throws SQLException
{
this.currentQueryNumber = currentQueryNumber;
if (currentQueryNumber == numberOfQueries - 1)
{
this.numberOfUnions = this.finalUnionNumber;
}
}
public void setMaxUnionCount(int maxUnionCount)
{
this.maxUnionCount = maxUnionCount;
}
public AnalyzedOperation getAnalyzedOperation()
{
return analyzedOperation;
}
public DatabaseType getDatabaseType()
{
return databaseType;
}
public int prepareQueryForSource(int sourceNumber, DatabaseType dt, TimeZone timeZone)
{
return prepareQueryForSource(sourceNumber, dt, timeZone, false);
}
public boolean isParallel()
{
return this.isParallel;
}
public int prepareQueryForSource(int sourceNumber, DatabaseType dt, TimeZone timeZone, boolean isParallel)
{
this.currentSourceNumber = sourceNumber;
this.timeZone = timeZone;
this.isParallel = isParallel;
getCurrentIdExtractor().reset();
this.databaseType = dt;
this.whereClause.clear();
if (this.derivedColumnSubstitutionMap != null)
{
this.derivedColumnSubstitutionMap.clear();
}
totalInClauseParameters = 0;
largeInClause = null;
numberOfChunksPerIn = 0;
numberOfQueries = 0;
numberOfUnions = 1;
finalUnionNumber = 1;
this.currentQueryNumber = 0;
firstWhereClause = null;
lastWhereClause = null;
currentUnionNumber = 0;
if (orderByClause != null)
{
orderByClause.setLength(0);
}
if (setOperationWhereClausePositionList != null)
{
setOperationWhereClausePositionList.clear();
}
prepareQuery();
return this.getNumberOfQueries();
}
private String safeToString()
{
try
{
return this.analyzedOperation.getOriginalOperation().toString();
}
catch(Throwable t)
{
// for badly constructed operations, even toString can fail.
return "";
}
}
private void prepareQuery()
{
Operation op = this.analyzedOperation.getAnalyzedOperation();
boolean foundAsOfAttributes = analyzedOperation.hasAsOfAttributes();
if (!preparedOnce)
{
clauseCount = op.getClauseCount(this);
if (foundAsOfAttributes)
{
ObjectWithMapperStack[] mapperStacks = analyzedOperation.getAllAsOfAttributes();
asOfAttributeWithMapperStackList = new FastList(mapperStacks.length);
for(ObjectWithMapperStack s: mapperStacks)
{
asOfAttributeWithMapperStackList.add(s);
}
for(int i=0;i this.databaseType.getMaxSearchableArguments();
}
public int getNumberOfUnions()
{
return this.numberOfUnions;
}
public boolean hasChunkedUnions(SetBasedAtomicOperation setBasedAtomicOperation)
{
return this.largeInClause != null && this.largeInClause.getOp().equals(setBasedAtomicOperation);
}
protected int getNumberOfQueries()
{
this.numberOfQueries = 1;
if (!mayNeedToSplit() || this.setOperationWhereClausePositionList == null)
{
return this.numberOfQueries;
}
int dbMaxClauses = this.databaseType.getMaxClauses();
int dbMaxSearchableArgs = this.databaseType.getMaxSearchableArguments();
int maxClauseCount = dbMaxClauses;
if (clauseCount - totalInClauseParameters > maxClauseCount)
{
logger.warn("Query has too many parameters and cannot be broken up. Max database params: "+
maxClauseCount+". Query has "+clauseCount+" parameters, of which "+totalInClauseParameters+" are large in-clauses.");
}
this.setOperationWhereClausePositionList.sort();
if (dbMaxClauses > dbMaxSearchableArgs)
{
int largestInClauseParamCount = ((SetBasedOpAndPosition)this.setOperationWhereClausePositionList.get(0)).getOp().getSetSize();
int minClauseCount = clauseCount - largestInClauseParamCount + (largestInClauseParamCount > 0 ? 10 : 0);
if (minClauseCount < dbMaxSearchableArgs)
{
maxClauseCount = dbMaxSearchableArgs;
}
}
int countSoFar = fillInSetBasedOperations(maxClauseCount);
if (largeInClause == null)
{
return this.numberOfQueries;
}
fillInSplitInClause(maxClauseCount, countSoFar);
return this.numberOfQueries;
}
private void fillInSplitInClause(int maxClauseCount, int countSoFar)
{
int totalLeft = maxClauseCount - countSoFar;
int totalNeeded = largeInClause.getOp().getSetSize();
numberOfChunksPerIn = totalNeeded / totalLeft;
if (totalNeeded % totalLeft > 0) numberOfChunksPerIn++;
this.numberOfUnions = numberOfChunksPerIn;
this.finalUnionNumber = numberOfChunksPerIn;
int maxUnionCount = getMaxUnionCount();
if (this.numberOfUnions > maxUnionCount)
{
this.numberOfQueries = (this.numberOfUnions/ maxUnionCount);
this.finalUnionNumber = this.numberOfUnions % maxUnionCount;
if (finalUnionNumber > 0)
{
this.numberOfQueries++;
}
else
{
finalUnionNumber = maxUnionCount;
}
this.numberOfUnions = maxUnionCount;
}
fillSplitWhereClause(largeInClause);
}
private int fillInSetBasedOperations(int maxClauseCount)
{
int countSoFar = clauseCount - totalInClauseParameters;
int totalInClauseLeft = totalInClauseParameters;
int fillRestIndex = -1;
for(int i=0;i maxClauseCount)
{
int setSize = opAndPosition.getOp().getSetSize();
if ((opAndPosition.isInsideAggregateJoin() || setSize > this.databaseType.getUseTempTableThreshold()))
{
replaceSetBasedWithTemp(opAndPosition);
totalInClauseLeft -= setSize;
}
else
{
// need to decide between using a temp table and in-clause splitting
if (countSoFar + totalInClauseLeft - setSize + 10 < maxClauseCount
&& maySplit(opAndPosition.getOp()) && largeInClause == null && !opAndPosition.isInExistsOrOrClause())
{
// split
largeInClause = opAndPosition;
fillRestIndex = i+1;
break;
}
else
{
// use temp table
replaceSetBasedWithTemp(opAndPosition);
totalInClauseLeft -= setSize;
}
}
}
else
{
fillRestIndex = i;
break;
}
}
countSoFar = fillRestOfSetBasedOperations(countSoFar, fillRestIndex);
return countSoFar;
}
private int fillRestOfSetBasedOperations(int countSoFar, int fillRestIndex)
{
if (fillRestIndex >= 0)
{
for(int i=fillRestIndex;i=0 ) return this.maxUnionCount;
return this.databaseType.getMaxUnionCount();
}
private void fillSplitWhereClause(SetBasedOpAndPosition opAndPosition)
{
SetBasedAtomicOperation setBasedAtomicOperation = opAndPosition.getOp();
int position = opAndPosition.getPosition();
int numberOfQuestions = setBasedAtomicOperation.getSetSize() / numberOfChunksPerIn;
StringBuilder firstWhereBuffer = new StringBuilder(this.whereClause.length() + numberOfQuestions * 2);
firstWhereBuffer.append(this.whereClause);
// now fix the where string
if ((setBasedAtomicOperation.getSetSize() % numberOfChunksPerIn) > 0) numberOfQuestions++;
String bunchOfQuestionMarks = createQuestionMarks(numberOfQuestions);
firstWhereBuffer.insert(position, bunchOfQuestionMarks);
numberOfQuestions = setBasedAtomicOperation.getSetSize() - ((numberOfChunksPerIn - 1) * numberOfQuestions);
bunchOfQuestionMarks = createQuestionMarks(numberOfQuestions);
StringBuilder lastWhereBuffer = new StringBuilder(this.whereClause.length() + numberOfQuestions * 2);
lastWhereBuffer.append(this.whereClause);
lastWhereBuffer.insert(position, bunchOfQuestionMarks);
this.firstWhereClause = firstWhereBuffer.toString();
this.lastWhereClause = lastWhereBuffer.toString();
}
private String createQuestionMarks(int numberOfQuestions)
{
int questionLength = (numberOfQuestions - 1) * 2 + 1;
StringBuilder bunchOfQuestionMarks = new StringBuilder(questionLength);
bunchOfQuestionMarks.append('?');
for (int k = 1; k < numberOfQuestions; k++)
{
bunchOfQuestionMarks.append(",?");
}
return bunchOfQuestionMarks.toString();
}
public int getNumberOfChunksPerIn()
{
return numberOfChunksPerIn;
}
public void setSetBasedClausePosition(SetBasedAtomicOperation setBasedAtomicOperation)
{
if (this.setOperationWhereClausePositionList == null)
{
this.setOperationWhereClausePositionList = new InternalList(4);
}
JoinClause joinClause = getCurrentIdExtractor().getCurrentJoinClause();
boolean belongsToInner = false;
WhereClause activeWhereClause = this.whereClause;
if (joinClause != null && joinClause.getWhereClause() != null)
{
belongsToInner = joinClause.belongsToInnerSql(this);
activeWhereClause = joinClause.getWhereClause();
}
int position = activeWhereClause.length() - 1;
SetBasedOpAndPosition opAndPos = new SetBasedOpAndPosition(setBasedAtomicOperation, position,
belongsToInner, activeWhereClause.isInOrClause(), joinClause);
this.setOperationWhereClausePositionList.add(opAndPos);
int setSize = setBasedAtomicOperation.getSetSize();
this.totalInClauseParameters += setSize;
}
public WhereClause getWhereClause()
{
return whereClause;
}
@Override
public WhereClause getParentWhereClause(SqlQuery sqlQuery)
{
return null;
}
public void setNotExistsForNextOperation()
{
this.notExists = true;
}
public void pushMapper(Mapper mapper)
{
JoinClause clause = getCurrentIdExtractor().pushMapperAndGetJoinClause(mapper);
clause.generateSql(this, this.notExists);
this.notExists = false;
}
public Mapper popMapper()
{
return getCurrentIdExtractor().popMapper();
}
public Mapper temporarilyPopMapper()
{
return getCurrentIdExtractor().popMapper();
}
public TimeZone getTimeZone() {
return timeZone;
}
public void pushMapperContainer(Object mapper)
{
getCurrentIdExtractor().pushMapperContainer(mapper);
}
public void popMapperContainer()
{
getCurrentIdExtractor().popMapperContainer();
}
public ObjectWithMapperStack constructWithMapperStack(Object o)
{
return getCurrentIdExtractor().constructWithMapperStack(o);
}
public ObjectWithMapperStack constructWithMapperStackWithoutLastMapper(Object o)
{
return getCurrentIdExtractor().constructWithMapperStackWithoutLastMapper(o);
}
public MapperStackImpl getCurrentMapperList()
{
return getCurrentIdExtractor().getCurrentMapperList();
}
public void clearMapperStack()
{
getCurrentIdExtractor().clearMapperStack();
}
public void addAsOfAttributeSql()
{
if (this.asOfAttributeWithMapperStackList != null)
{
MapperStackImpl currentMapperStack = getCurrentIdExtractor().getCurrentMapperList();
for(int i=0;i 1 && requiresDistinct();
}
public TupleTempContext getMultiInTempContext(MultiInOperation multiInOperation)
{
return this.analyzedOperation.getAsOfEqualityChecker().getOrCreateMultiInTempContext(multiInOperation);
}
public void registerTempTupleMapper(Mapper mapper)
{
mapper.registerOperation(this.getIdExtractor(), true);
this.getCurrentIdExtractor().getCurrentJoinClause().setMapped(false);
mapper.popMappers(this);
}
public void addDerivedColumnSubstitution(String fullyQualifiedColumn, String derivedColumnName, WhereClause whereClause)
{
if (this.derivedColumnSubstitutionMap == null)
{
this.derivedColumnSubstitutionMap = UnifiedMap.newMap();
}
if (!this.derivedColumnSubstitutionMap.containsKey(fullyQualifiedColumn))
{
this.derivedColumnSubstitutionMap.put(fullyQualifiedColumn, derivedColumnName);
}
whereClause.addReachableColumn(fullyQualifiedColumn);
}
public String getColumnNameWithDerivedTableSubstitution(String fullyQualifiedColumnName, WhereClause whereClause)
{
if (this.derivedColumnSubstitutionMap == null || whereClause.isColumnReachable(fullyQualifiedColumnName))
{
return fullyQualifiedColumnName;
}
String subst = this.derivedColumnSubstitutionMap.get(fullyQualifiedColumnName);
return subst == null ? fullyQualifiedColumnName : subst;
}
private static class SetBasedOpAndPosition implements Comparable
{
private boolean inOrClause;
private boolean inExistsClause;
private SetBasedAtomicOperation op;
private int position;
private JoinClause joinClause;
private SetBasedOpAndPosition(SetBasedAtomicOperation op, int position, boolean inExistsClause, boolean inOrClause, JoinClause joinClause)
{
this.op = op;
this.position = position;
this.inExistsClause = inExistsClause;
this.inOrClause = inOrClause;
this.joinClause = joinClause;
}
public int getPosition()
{
return position;
}
public boolean isInOrClause()
{
return inOrClause;
}
public boolean isInExistsOrOrClause()
{
return inExistsClause || inOrClause;
}
public SetBasedAtomicOperation getOp()
{
return op;
}
public int compareTo(Object o)
{
// reverse sort
return ((SetBasedOpAndPosition)o).op.getSetSize() - this.op.getSetSize();
}
public void incrementPosition(int inc, SetBasedOpAndPosition filledOp)
{
if (this.hasSameWhereClause(filledOp) && this.position > filledOp.getPosition())
{
this.position += inc;
}
}
public void incrementPosition(int position, int inc, WhereClause activeWhereClause)
{
if (this.hasSameWhereClause(activeWhereClause) && this.position > position)
{
this.position += inc;
}
}
private boolean hasSameWhereClause(WhereClause activeWhereClause)
{
if (this.joinClause != null && this.joinClause.getWhereClause() != null)
{
return this.joinClause.getWhereClause() == activeWhereClause;
}
return activeWhereClause.getOwner() instanceof SqlQuery;
}
private boolean hasSameWhereClause(SetBasedOpAndPosition setBasedOpAndPosition)
{
JoinClause otherJoinClause = setBasedOpAndPosition.joinClause;
return hasSameWhereClause(otherJoinClause);
}
private boolean hasSameWhereClause(JoinClause otherJoinClause)
{
if (this.joinClause == otherJoinClause) // also takes care of null
{
return true;
}
if (this.joinClause != null)
{
return this.joinClause.hasSameWhereClause(otherJoinClause);
}
return otherJoinClause.hasSameWhereClause(this.joinClause);
}
public void insertSql(String sql, SqlQuery query)
{
if (this.joinClause == null || this.joinClause.getWhereClause() == null)
{
query.insertWhereWithoutShift(this.position, sql);
}
else
{
this.joinClause.insertWhereSql(this.position, sql);
}
}
public boolean isInsideAggregateJoin()
{
return this.joinClause != null && this.joinClause.isAggregateJoin();
}
public boolean allowsInClauseTempJoinReplacement(SqlQuery query)
{
return query.allowsInClauseTempJoinReplacement(this.joinClause);
}
public void restoreMapper(SqlQuery sqlQuery)
{
if (this.joinClause != null)
{
this.joinClause.restoreMapper(sqlQuery);
}
}
}
protected void insertWhereWithoutShift(int position, String sql)
{
this.whereClause.insert(position, sql);
}
protected Map getRawMapperStackToJoinClauseMap()
{
return getCurrentIdExtractor().getRawMapperStackToJoinClauseMap();
}
protected MithraDatabaseIdentifierExtractor getIdExtractor()
{
return this.idExtractor;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy