use of org.datanucleus.store.rdbms.table.JoinTable in project datanucleus-rdbms by datanucleus.
the class QueryToSQLMapper method processPrimaryExpression.
/* (non-Javadoc)
* @see org.datanucleus.query.evaluator.AbstractExpressionEvaluator#processPrimaryExpression(org.datanucleus.query.expression.PrimaryExpression)
*/
protected Object processPrimaryExpression(PrimaryExpression expr) {
SQLExpression sqlExpr = null;
if (expr.getLeft() != null) {
if (expr.getLeft() instanceof DyadicExpression && expr.getLeft().getOperator() == Expression.OP_CAST) {
String exprCastName = null;
if (expr.getLeft().getLeft() instanceof PrimaryExpression) {
exprCastName = "CAST_" + ((PrimaryExpression) expr.getLeft().getLeft()).getId();
} else if (expr.getLeft().getLeft() instanceof VariableExpression) {
exprCastName = "CAST_" + ((VariableExpression) expr.getLeft().getLeft()).getId();
} else if (expr.getLeft().getLeft() instanceof InvokeExpression) {
exprCastName = "CAST_" + expr.getLeft().getLeft();
} else {
throw new NucleusException("Don't currently support cast of " + expr.getLeft().getLeft());
}
expr.getLeft().getLeft().evaluate(this);
sqlExpr = stack.pop();
JavaTypeMapping mapping = sqlExpr.getJavaTypeMapping();
if (mapping instanceof EmbeddedMapping) {
// Cast of an embedded field, so use same table
// Extract what we are casting it to
Literal castLitExpr = (Literal) expr.getLeft().getRight();
Class castType = resolveClass((String) castLitExpr.getLiteral());
AbstractClassMetaData castCmd = ec.getMetaDataManager().getMetaDataForClass(castType, clr);
JavaTypeMapping discMapping = ((EmbeddedMapping) mapping).getDiscriminatorMapping();
if (discMapping != null) {
// Should have a discriminator always when casting this
SQLExpression discExpr = exprFactory.newExpression(stmt, sqlExpr.getSQLTable(), discMapping);
Object discVal = castCmd.getDiscriminatorValue();
SQLExpression discValExpr = exprFactory.newLiteral(stmt, discMapping, discVal);
BooleanExpression discRestrictExpr = discExpr.eq(discValExpr);
Iterator<String> subclassIter = storeMgr.getSubClassesForClass(castType.getName(), true, clr).iterator();
while (subclassIter.hasNext()) {
String subclassName = subclassIter.next();
AbstractClassMetaData subtypeCmd = storeMgr.getMetaDataManager().getMetaDataForClass(subclassName, clr);
discVal = subtypeCmd.getDiscriminatorValue();
discValExpr = exprFactory.newLiteral(stmt, discMapping, discVal);
BooleanExpression subtypeExpr = discExpr.eq(discValExpr);
discRestrictExpr = discRestrictExpr.ior(subtypeExpr);
}
stmt.whereAnd(discRestrictExpr, true);
}
SQLTableMapping tblMapping = new SQLTableMapping(sqlExpr.getSQLTable(), castCmd, sqlExpr.getJavaTypeMapping());
setSQLTableMappingForAlias(exprCastName, tblMapping);
SQLTableMapping sqlMapping = getSQLTableMappingForPrimaryExpression(stmt, exprCastName, expr, Boolean.FALSE);
if (sqlMapping == null) {
throw new NucleusException("PrimaryExpression " + expr + " is not yet supported");
}
sqlExpr = exprFactory.newExpression(stmt, sqlMapping.table, sqlMapping.mapping);
stack.push(sqlExpr);
return sqlExpr;
}
// Evaluate the cast
expr.getLeft().evaluate(this);
sqlExpr = stack.pop();
// Extract what we are casting it to
Literal castLitExpr = (Literal) expr.getLeft().getRight();
AbstractClassMetaData castCmd = ec.getMetaDataManager().getMetaDataForClass(resolveClass((String) castLitExpr.getLiteral()), clr);
SQLTableMapping tblMapping = new SQLTableMapping(sqlExpr.getSQLTable(), castCmd, sqlExpr.getJavaTypeMapping());
setSQLTableMappingForAlias(exprCastName, tblMapping);
SQLTableMapping sqlMapping = getSQLTableMappingForPrimaryExpression(stmt, exprCastName, expr, Boolean.FALSE);
if (sqlMapping == null) {
throw new NucleusException("PrimaryExpression " + expr + " is not yet supported");
}
sqlExpr = exprFactory.newExpression(stmt, sqlMapping.table, sqlMapping.mapping);
stack.push(sqlExpr);
return sqlExpr;
} else if (expr.getLeft() instanceof ParameterExpression) {
// "{paramExpr}.field[.field[.field]]"
// Need parameter values to process this
setNotPrecompilable();
ParameterExpression paramExpr = (ParameterExpression) expr.getLeft();
Symbol paramSym = compilation.getSymbolTable().getSymbol(paramExpr.getId());
if (paramSym.getValueType() != null && paramSym.getValueType().isArray()) {
// Special case : array "methods" (particularly "length")
String first = expr.getTuples().get(0);
processParameterExpression(paramExpr, true);
SQLExpression paramSqlExpr = stack.pop();
sqlExpr = exprFactory.invokeMethod(stmt, "ARRAY", first, paramSqlExpr, null);
stack.push(sqlExpr);
return sqlExpr;
}
// Create Literal for the parameter (since we need to perform operations on it)
processParameterExpression(paramExpr, true);
SQLExpression paramSqlExpr = stack.pop();
SQLLiteral lit = (SQLLiteral) paramSqlExpr;
Object paramValue = lit.getValue();
List<String> tuples = expr.getTuples();
Iterator<String> tuplesIter = tuples.iterator();
Object objValue = paramValue;
while (tuplesIter.hasNext()) {
String fieldName = tuplesIter.next();
if (objValue == null) {
NucleusLogger.QUERY.warn(">> Compilation of " + expr + " : need to direct through field \"" + fieldName + "\" on null value, hence not compilable!");
// Null value, and we have further path to navigate TODO Handle this "NPE"
break;
}
objValue = getValueForObjectField(objValue, fieldName);
// Using literal value of parameter, so cannot precompile it
setNotPrecompilable();
}
if (objValue == null) {
sqlExpr = exprFactory.newLiteral(stmt, null, null);
stack.push(sqlExpr);
return sqlExpr;
}
JavaTypeMapping m = exprFactory.getMappingForType(objValue.getClass(), false);
sqlExpr = exprFactory.newLiteral(stmt, m, objValue);
stack.push(sqlExpr);
return sqlExpr;
} else if (expr.getLeft() instanceof VariableExpression) {
// "{varExpr}.field[.field[.field]]"
VariableExpression varExpr = (VariableExpression) expr.getLeft();
processVariableExpression(varExpr);
SQLExpression varSqlExpr = stack.pop();
if (varSqlExpr instanceof UnboundExpression) {
// Bind as CROSS JOIN for now
processUnboundExpression((UnboundExpression) varSqlExpr);
varSqlExpr = stack.pop();
}
Class varType = clr.classForName(varSqlExpr.getJavaTypeMapping().getType());
if (varSqlExpr.getSQLStatement() == stmt.getParentStatement()) {
// Use parent mapper to get the mapping for this field since it has the table
SQLTableMapping sqlMapping = parentMapper.getSQLTableMappingForPrimaryExpression(stmt, null, expr, Boolean.FALSE);
if (sqlMapping == null) {
throw new NucleusException("PrimaryExpression " + expr.getId() + " is not yet supported");
}
// TODO Cater for the table required to join to not being the primary table of the outer query
// This should check on
// getDatastoreAdapter().supportsOption(RDBMSAdapter.ACCESS_PARENTQUERY_IN_SUBQUERY))
sqlExpr = exprFactory.newExpression(varSqlExpr.getSQLStatement(), sqlMapping.table, sqlMapping.mapping);
stack.push(sqlExpr);
return sqlExpr;
}
SQLTableMapping varTblMapping = getSQLTableMappingForAlias(varExpr.getId());
if (varTblMapping == null) {
throw new NucleusUserException("Variable " + varExpr.getId() + " is not yet bound, so cannot get field " + expr.getId());
}
if (varTblMapping.cmd == null) {
throw new NucleusUserException("Variable " + varExpr.getId() + " of type " + varType.getName() + " cannot evaluate " + expr.getId());
}
SQLTableMapping sqlMapping = getSQLTableMappingForPrimaryExpression(varSqlExpr.getSQLStatement(), varExpr.getId(), expr, Boolean.FALSE);
sqlExpr = exprFactory.newExpression(sqlMapping.table.getSQLStatement(), sqlMapping.table, sqlMapping.mapping);
stack.push(sqlExpr);
return sqlExpr;
} else if (expr.getLeft() instanceof InvokeExpression) {
InvokeExpression invokeExpr = (InvokeExpression) expr.getLeft();
SQLExpression invokedSqlExpr = getInvokedSqlExpressionForInvokeExpression(invokeExpr);
processInvokeExpression(invokeExpr, invokedSqlExpr);
SQLExpression invokeSqlExpr = stack.pop();
Table tbl = invokeSqlExpr.getSQLTable().getTable();
if (expr.getTuples().size() > 1) {
throw new NucleusUserException("Dont currently support evaluating " + expr.getId() + " on " + invokeSqlExpr);
}
SQLTable invokeSqlTbl = invokeSqlExpr.getSQLTable();
if (invokedSqlExpr.getJavaTypeMapping() instanceof OptionalMapping && invokeExpr.getOperation().equals("get") && expr.getTuples().size() == 1) {
OptionalMapping opMapping = (OptionalMapping) invokedSqlExpr.getJavaTypeMapping();
if (opMapping.getWrappedMapping() instanceof PersistableMapping) {
// Special case of Optional.get().{field}, so we need to join to the related table
AbstractMemberMetaData mmd = invokedSqlExpr.getJavaTypeMapping().getMemberMetaData();
AbstractClassMetaData otherCmd = ec.getMetaDataManager().getMetaDataForClass(mmd.getCollection().getElementType(), clr);
Table otherTbl = storeMgr.getDatastoreClass(otherCmd.getFullClassName(), clr);
// Optional type so do LEFT OUTER JOIN since if it is null then we would eliminate all other results
invokeSqlTbl = stmt.join(JoinType.LEFT_OUTER_JOIN, invokeSqlExpr.getSQLTable(), opMapping.getWrappedMapping(), otherTbl, null, otherTbl.getIdMapping(), null, null, true);
tbl = invokeSqlTbl.getTable();
}
}
if (tbl instanceof DatastoreClass) {
// Table of a class, so assume to have field in the table of the class
// TODO Allow joins to superclasses if required
JavaTypeMapping mapping = ((DatastoreClass) tbl).getMemberMapping(expr.getId());
if (mapping == null) {
throw new NucleusUserException("Dont currently support evaluating " + expr.getId() + " on " + invokeSqlExpr + ". The field " + expr.getId() + " doesnt exist in table " + tbl);
}
sqlExpr = exprFactory.newExpression(stmt, invokeSqlTbl, mapping);
stack.push(sqlExpr);
return sqlExpr;
} else if (tbl instanceof JoinTable) {
if (invokeSqlExpr.getJavaTypeMapping() instanceof EmbeddedMapping) {
// Table containing an embedded element/key/value so assume we have a column in the join table
EmbeddedMapping embMapping = (EmbeddedMapping) invokeSqlExpr.getJavaTypeMapping();
JavaTypeMapping mapping = embMapping.getJavaTypeMapping(expr.getId());
if (mapping == null) {
throw new NucleusUserException("Dont currently support evaluating " + expr.getId() + " on " + invokeSqlExpr + ". The field " + expr.getId() + " doesnt exist in table " + tbl);
}
sqlExpr = exprFactory.newExpression(stmt, invokeSqlTbl, mapping);
stack.push(sqlExpr);
return sqlExpr;
}
}
throw new NucleusUserException("Dont currently support evaluating " + expr.getId() + " on " + invokeSqlExpr + " with invoke having table of " + tbl);
} else {
throw new NucleusUserException("Dont currently support PrimaryExpression with 'left' of " + expr.getLeft());
}
}
// Real primary expression ("field.field", "alias.field.field" etc)
SQLTableMapping sqlMapping = getSQLTableMappingForPrimaryExpression(stmt, null, expr, null);
if (sqlMapping == null) {
throw new NucleusException("PrimaryExpression " + expr.getId() + " is not yet supported");
}
sqlExpr = exprFactory.newExpression(stmt, sqlMapping.table, sqlMapping.mapping);
if (sqlMapping.mmd != null && sqlExpr instanceof MapExpression) {
// This sqlMapping is for something joined in a FROM clause, so set the alias on the returned MapExpression to avoid doing the same joins
String alias = getAliasForSQLTableMapping(sqlMapping);
if (alias == null && parentMapper != null) {
alias = parentMapper.getAliasForSQLTableMapping(sqlMapping);
}
((MapExpression) sqlExpr).setAliasForMapTable(alias);
}
stack.push(sqlExpr);
return sqlExpr;
}
use of org.datanucleus.store.rdbms.table.JoinTable in project datanucleus-rdbms by datanucleus.
the class BulkFetchExistsHandler method getStatementToBulkFetchField.
/**
* Convenience method to generate a bulk-fetch statement for the specified multi-valued field of the owning query.
* @param candidateCmd Metadata for the candidate
* @param parameters Parameters for the query
* @param mmd Metadata for the multi-valued field
* @param datastoreCompilation The datastore compilation of the query
* @param mapperOptions Any options for the query to SQL mapper
* @return The bulk-fetch statement for retrieving this multi-valued field.
*/
public IteratorStatement getStatementToBulkFetchField(AbstractClassMetaData candidateCmd, AbstractMemberMetaData mmd, Query query, Map parameters, RDBMSQueryCompilation datastoreCompilation, Set<String> mapperOptions) {
IteratorStatement iterStmt = null;
ExecutionContext ec = query.getExecutionContext();
ClassLoaderResolver clr = ec.getClassLoaderResolver();
RDBMSStoreManager storeMgr = (RDBMSStoreManager) query.getStoreManager();
Store backingStore = storeMgr.getBackingStoreForField(clr, mmd, null);
if (backingStore instanceof JoinSetStore || backingStore instanceof JoinListStore || backingStore instanceof JoinArrayStore) {
// Set/List/array using join-table : Generate an iterator query of the form
if (backingStore instanceof JoinSetStore) {
iterStmt = ((JoinSetStore) backingStore).getIteratorStatement(ec, ec.getFetchPlan(), false);
} else if (backingStore instanceof JoinListStore) {
iterStmt = ((JoinListStore) backingStore).getIteratorStatement(ec, ec.getFetchPlan(), false, -1, -1);
} else if (backingStore instanceof JoinArrayStore) {
iterStmt = ((JoinArrayStore) backingStore).getIteratorStatement(ec, ec.getFetchPlan(), false);
} else {
throw new NucleusUserException("We do not support BulkFetch using EXISTS for backingStore = " + backingStore);
}
// SELECT ELEM_TBL.COL1, ELEM_TBL.COL2, ... FROM JOIN_TBL INNER_JOIN ELEM_TBL WHERE JOIN_TBL.ELEMENT_ID = ELEM_TBL.ID
// AND EXISTS (SELECT OWNER_TBL.ID FROM OWNER_TBL WHERE (queryWhereClause) AND JOIN_TBL.OWNER_ID = OWNER_TBL.ID)
SelectStatement sqlStmt = iterStmt.getSelectStatement();
JoinTable joinTbl = (JoinTable) sqlStmt.getPrimaryTable().getTable();
JavaTypeMapping joinOwnerMapping = joinTbl.getOwnerMapping();
// Generate the EXISTS subquery (based on the JDOQL/JPQL query)
SelectStatement existsStmt = RDBMSQueryUtils.getStatementForCandidates(storeMgr, sqlStmt, candidateCmd, datastoreCompilation.getResultDefinitionForClass(), ec, query.getCandidateClass(), query.isSubclasses(), query.getResult(), null, null, null);
Set<String> options = new HashSet<>();
if (mapperOptions != null) {
options.addAll(mapperOptions);
}
options.add(QueryToSQLMapper.OPTION_SELECT_CANDIDATE_ID_ONLY);
QueryToSQLMapper sqlMapper = new QueryToSQLMapper(existsStmt, query.getCompilation(), parameters, null, null, candidateCmd, query.isSubclasses(), query.getFetchPlan(), ec, query.getParsedImports(), options, query.getExtensions());
sqlMapper.compile();
// Add EXISTS clause on iterator statement so we can restrict to just the owners in this query
// ORDER BY in EXISTS is forbidden by some RDBMS
existsStmt.setOrdering(null, null);
BooleanExpression existsExpr = new BooleanSubqueryExpression(sqlStmt, "EXISTS", existsStmt);
sqlStmt.whereAnd(existsExpr, true);
// Join to outer statement so we restrict to collection elements for the query candidates
SQLExpression joinTblOwnerExpr = sqlStmt.getRDBMSManager().getSQLExpressionFactory().newExpression(sqlStmt, sqlStmt.getPrimaryTable(), joinOwnerMapping);
SQLExpression existsOwnerExpr = sqlStmt.getRDBMSManager().getSQLExpressionFactory().newExpression(existsStmt, existsStmt.getPrimaryTable(), existsStmt.getPrimaryTable().getTable().getIdMapping());
existsStmt.whereAnd(joinTblOwnerExpr.eq(existsOwnerExpr), true);
// Select the owner candidate so we can separate the collection elements out to their owner
int[] ownerColIndexes = sqlStmt.select(joinTblOwnerExpr, null);
StatementMappingIndex ownerMapIdx = new StatementMappingIndex(existsStmt.getPrimaryTable().getTable().getIdMapping());
ownerMapIdx.setColumnPositions(ownerColIndexes);
iterStmt.setOwnerMapIndex(ownerMapIdx);
} else if (backingStore instanceof FKSetStore || backingStore instanceof FKListStore || backingStore instanceof FKArrayStore) {
if (backingStore instanceof FKSetStore) {
iterStmt = ((FKSetStore) backingStore).getIteratorStatement(ec, ec.getFetchPlan(), false);
} else if (backingStore instanceof FKListStore) {
iterStmt = ((FKListStore) backingStore).getIteratorStatement(ec, ec.getFetchPlan(), false, -1, -1);
} else if (backingStore instanceof FKArrayStore) {
iterStmt = ((FKArrayStore) backingStore).getIteratorStatement(ec, ec.getFetchPlan(), false);
} else {
throw new NucleusUserException("We do not support BulkFetch using EXISTS for backingStore = " + backingStore);
}
// Set/List/array using foreign-key : Generate an iterator query of the form
// SELECT ELEM_TBL.COL1, ELEM_TBL.COL2, ... FROM ELEM_TBL
// WHERE EXISTS (SELECT OWNER_TBL.ID FROM OWNER_TBL WHERE (queryWhereClause) AND ELEM_TBL.OWNER_ID = OWNER_TBL.ID)
SelectStatement sqlStmt = iterStmt.getSelectStatement();
// Generate the EXISTS subquery (based on the JDOQL/JPQL query)
SelectStatement existsStmt = RDBMSQueryUtils.getStatementForCandidates(storeMgr, sqlStmt, candidateCmd, datastoreCompilation.getResultDefinitionForClass(), ec, query.getCandidateClass(), query.isSubclasses(), query.getResult(), null, null, null);
Set<String> options = new HashSet<>();
if (mapperOptions != null) {
options.addAll(mapperOptions);
}
options.add(QueryToSQLMapper.OPTION_SELECT_CANDIDATE_ID_ONLY);
QueryToSQLMapper sqlMapper = new QueryToSQLMapper(existsStmt, query.getCompilation(), parameters, null, null, candidateCmd, query.isSubclasses(), query.getFetchPlan(), ec, query.getParsedImports(), options, query.getExtensions());
sqlMapper.compile();
// Add EXISTS clause on iterator statement so we can restrict to just the owners in this query
// ORDER BY in EXISTS is forbidden by some RDBMS
existsStmt.setOrdering(null, null);
BooleanExpression existsExpr = new BooleanSubqueryExpression(sqlStmt, "EXISTS", existsStmt);
sqlStmt.whereAnd(existsExpr, true);
// Join to outer statement so we restrict to collection elements for the query candidates
SQLExpression elemTblOwnerExpr = sqlStmt.getRDBMSManager().getSQLExpressionFactory().newExpression(sqlStmt, sqlStmt.getPrimaryTable(), ((BaseContainerStore) backingStore).getOwnerMapping());
SQLExpression existsOwnerExpr = sqlStmt.getRDBMSManager().getSQLExpressionFactory().newExpression(existsStmt, existsStmt.getPrimaryTable(), existsStmt.getPrimaryTable().getTable().getIdMapping());
existsStmt.whereAnd(elemTblOwnerExpr.eq(existsOwnerExpr), true);
// Select the owner candidate so we can separate the collection elements out to their owner
int[] ownerColIndexes = sqlStmt.select(elemTblOwnerExpr, null);
StatementMappingIndex ownerMapIdx = new StatementMappingIndex(existsStmt.getPrimaryTable().getTable().getIdMapping());
ownerMapIdx.setColumnPositions(ownerColIndexes);
iterStmt.setOwnerMapIndex(ownerMapIdx);
}
return iterStmt;
}
use of org.datanucleus.store.rdbms.table.JoinTable in project datanucleus-rdbms by datanucleus.
the class QueryToSQLMapper method processFromClauseSubquery.
/**
* Method to process a ClassExpression where it represents a subquery.
* User defined the candidate of the subquery as an implied join to the outer query, for example "SELECT c FROM Customer c WHERE EXISTS (SELECT o FROM c.orders o ...)"
* so this method will add the join(s) to the outer query.
* @param clsExpr The ClassExpression
* @param candSqlTbl Candidate SQL Table
* @param mmgr MetaData Manager
*/
protected void processFromClauseSubquery(ClassExpression clsExpr, SQLTable candSqlTbl, MetaDataManager mmgr) {
String[] tokens = StringUtils.split(clsExpr.getCandidateExpression(), ".");
String leftAlias = tokens[0];
SQLTableMapping outerSqlTblMapping = parentMapper.getSQLTableMappingForAlias(leftAlias);
AbstractClassMetaData leftCmd = outerSqlTblMapping.cmd;
// Get array of the left-right sides of this expression so we can work back from the subquery candidate
AbstractMemberMetaData[] leftMmds = new AbstractMemberMetaData[tokens.length - 1];
AbstractMemberMetaData[] rightMmds = new AbstractMemberMetaData[tokens.length - 1];
for (int i = 0; i < tokens.length - 1; i++) {
String joinedField = tokens[i + 1];
AbstractMemberMetaData leftMmd = leftCmd.getMetaDataForMember(joinedField);
AbstractMemberMetaData rightMmd = null;
AbstractClassMetaData rightCmd = null;
RelationType relationType = leftMmd.getRelationType(clr);
if (RelationType.isBidirectional(relationType)) {
// Take first possible
rightMmd = leftMmd.getRelatedMemberMetaData(clr)[0];
rightCmd = rightMmd.getAbstractClassMetaData();
} else if (relationType == RelationType.ONE_TO_ONE_UNI) {
rightCmd = mmgr.getMetaDataForClass(leftMmd.getType(), clr);
} else if (relationType == RelationType.ONE_TO_MANY_UNI) {
if (leftMmd.hasCollection()) {
rightCmd = mmgr.getMetaDataForClass(leftMmd.getCollection().getElementType(), clr);
} else if (leftMmd.hasMap()) {
rightCmd = mmgr.getMetaDataForClass(leftMmd.getMap().getValueType(), clr);
}
} else {
throw new NucleusUserException("Subquery has been specified with a candidate-expression that includes \"" + tokens[i] + "\" that isnt a relation field!!");
}
leftMmds[i] = leftMmd;
rightMmds[i] = rightMmd;
leftCmd = rightCmd;
}
// Work from subquery candidate back to outer query table, adding joins and where clause as appropriate
SQLTable rSqlTbl = candSqlTbl;
SQLTable outerSqlTbl = outerSqlTblMapping.table;
JoinType joinType = JoinType.INNER_JOIN;
for (int i = leftMmds.length - 1; i >= 0; i--) {
AbstractMemberMetaData leftMmd = leftMmds[i];
AbstractMemberMetaData rightMmd = rightMmds[i];
DatastoreClass leftTbl = storeMgr.getDatastoreClass(leftMmd.getClassName(true), clr);
SQLTable lSqlTbl = null;
RelationType relationType = leftMmd.getRelationType(clr);
if (relationType == RelationType.ONE_TO_ONE_UNI) {
// 1-1 with FK in left table
if (i == 0) {
// Add where clause right table to outer table
SQLExpression outerExpr = exprFactory.newExpression(outerSqlTbl.getSQLStatement(), outerSqlTbl, outerSqlTbl.getTable().getMemberMapping(leftMmd));
SQLExpression rightExpr = exprFactory.newExpression(stmt, rSqlTbl, rSqlTbl.getTable().getIdMapping());
stmt.whereAnd(outerExpr.eq(rightExpr), false);
} else {
// Join to left table
JavaTypeMapping leftMapping = leftTbl.getMemberMapping(leftMmd);
lSqlTbl = stmt.join(joinType, rSqlTbl, rSqlTbl.getTable().getIdMapping(), leftTbl, null, leftMapping, null, null, true);
}
} else if (relationType == RelationType.ONE_TO_ONE_BI) {
if (leftMmd.getMappedBy() != null) {
// 1-1 with FK in right table
JavaTypeMapping rightMapping = rSqlTbl.getTable().getMemberMapping(rightMmd);
if (i == 0) {
// Add where clause right table to outer table
SQLExpression outerExpr = exprFactory.newExpression(outerSqlTbl.getSQLStatement(), outerSqlTbl, outerSqlTbl.getTable().getIdMapping());
SQLExpression rightExpr = exprFactory.newExpression(stmt, rSqlTbl, rightMapping);
stmt.whereAnd(outerExpr.eq(rightExpr), false);
} else {
// Join to left table
lSqlTbl = stmt.join(joinType, rSqlTbl, rightMapping, leftTbl, null, leftTbl.getIdMapping(), null, null, true);
}
} else {
// 1-1 with FK in left table
if (i == 0) {
// Add where clause right table to outer table
SQLExpression outerExpr = exprFactory.newExpression(outerSqlTbl.getSQLStatement(), outerSqlTbl, outerSqlTbl.getTable().getMemberMapping(leftMmd));
SQLExpression rightExpr = exprFactory.newExpression(stmt, rSqlTbl, rSqlTbl.getTable().getIdMapping());
stmt.whereAnd(outerExpr.eq(rightExpr), false);
} else {
// Join to left table
lSqlTbl = stmt.join(joinType, rSqlTbl, rSqlTbl.getTable().getIdMapping(), leftTbl, null, leftTbl.getMemberMapping(leftMmd), null, null, true);
}
}
} else if (relationType == RelationType.ONE_TO_MANY_UNI) {
if (leftMmd.getJoinMetaData() != null || rightMmd.getJoinMetaData() != null) {
// 1-N with join table to right table, so join from right to join table
JoinTable joinTbl = (JoinTable) storeMgr.getTable(leftMmd);
SQLTable joinSqlTbl = null;
if (leftMmd.hasCollection()) {
joinSqlTbl = stmt.join(joinType, rSqlTbl, rSqlTbl.getTable().getIdMapping(), joinTbl, null, ((ElementContainerTable) joinTbl).getElementMapping(), null, null, true);
} else if (leftMmd.hasMap()) {
joinSqlTbl = stmt.join(joinType, rSqlTbl, rSqlTbl.getTable().getIdMapping(), joinTbl, null, ((MapTable) joinTbl).getValueMapping(), null, null, true);
}
if (i == 0) {
// Add where clause join table (owner) to outer table (id)
SQLExpression outerExpr = exprFactory.newExpression(outerSqlTbl.getSQLStatement(), outerSqlTbl, outerSqlTbl.getTable().getIdMapping());
SQLExpression joinExpr = exprFactory.newExpression(stmt, joinSqlTbl, joinTbl.getOwnerMapping());
stmt.whereAnd(outerExpr.eq(joinExpr), false);
} else {
// Join to left table
lSqlTbl = stmt.join(joinType, joinSqlTbl, joinTbl.getOwnerMapping(), leftTbl, null, leftTbl.getIdMapping(), null, null, true);
}
} else {
// 1-N with FK in right table
if (i == 0) {
// Add where clause right table to outer table
SQLExpression outerExpr = exprFactory.newExpression(outerSqlTbl.getSQLStatement(), outerSqlTbl, outerSqlTbl.getTable().getMemberMapping(leftMmd));
SQLExpression rightExpr = exprFactory.newExpression(stmt, rSqlTbl, rSqlTbl.getTable().getMemberMapping(rightMmd));
stmt.whereAnd(outerExpr.eq(rightExpr), false);
} else {
// Join to left table
lSqlTbl = stmt.join(joinType, rSqlTbl, rSqlTbl.getTable().getMemberMapping(rightMmd), leftTbl, null, leftTbl.getIdMapping(), null, null, true);
}
}
} else if (relationType == RelationType.ONE_TO_MANY_BI) {
if (leftMmd.getJoinMetaData() != null || rightMmd.getJoinMetaData() != null) {
// 1-N with join table to right table, so join from right to join table
JoinTable joinTbl = (JoinTable) storeMgr.getTable(leftMmd);
SQLTable joinSqlTbl = null;
if (leftMmd.hasCollection()) {
joinSqlTbl = stmt.join(joinType, rSqlTbl, rSqlTbl.getTable().getIdMapping(), joinTbl, null, ((ElementContainerTable) joinTbl).getElementMapping(), null, null, true);
} else if (leftMmd.hasMap()) {
joinSqlTbl = stmt.join(joinType, rSqlTbl, rSqlTbl.getTable().getIdMapping(), joinTbl, null, ((MapTable) joinTbl).getValueMapping(), null, null, true);
}
if (i == 0) {
// Add where clause join table (owner) to outer table (id)
SQLExpression outerExpr = exprFactory.newExpression(outerSqlTbl.getSQLStatement(), outerSqlTbl, outerSqlTbl.getTable().getIdMapping());
SQLExpression joinExpr = exprFactory.newExpression(stmt, joinSqlTbl, joinTbl.getOwnerMapping());
stmt.whereAnd(outerExpr.eq(joinExpr), false);
} else {
// Join to left table
lSqlTbl = stmt.join(joinType, joinSqlTbl, joinTbl.getOwnerMapping(), leftTbl, null, leftTbl.getIdMapping(), null, null, true);
}
} else {
// 1-N with FK in right table
if (i == 0) {
// Add where clause right table to outer table
SQLExpression outerExpr = exprFactory.newExpression(outerSqlTbl.getSQLStatement(), outerSqlTbl, outerSqlTbl.getTable().getIdMapping());
SQLExpression rightExpr = exprFactory.newExpression(stmt, rSqlTbl, rSqlTbl.getTable().getMemberMapping(rightMmd));
stmt.whereAnd(outerExpr.eq(rightExpr), false);
} else {
// Join to left table
lSqlTbl = stmt.join(joinType, rSqlTbl, rSqlTbl.getTable().getMemberMapping(rightMmd), leftTbl, null, leftTbl.getIdMapping(), null, null, true);
}
}
} else if (relationType == RelationType.MANY_TO_ONE_BI) {
if (leftMmd.getJoinMetaData() != null || rightMmd.getJoinMetaData() != null) {
// 1-N with join table to right table, so join from right to join table
JoinTable joinTbl = (JoinTable) storeMgr.getTable(leftMmd);
SQLTable joinSqlTbl = stmt.join(joinType, rSqlTbl, rSqlTbl.getTable().getIdMapping(), joinTbl, null, joinTbl.getOwnerMapping(), null, null, true);
if (leftMmd.hasCollection()) {
if (i == 0) {
// Add where clause join table (element) to outer table (id)
SQLExpression outerExpr = exprFactory.newExpression(outerSqlTbl.getSQLStatement(), outerSqlTbl, outerSqlTbl.getTable().getIdMapping());
SQLExpression joinExpr = exprFactory.newExpression(stmt, joinSqlTbl, ((ElementContainerTable) joinTbl).getElementMapping());
stmt.whereAnd(outerExpr.eq(joinExpr), false);
} else {
// Join to left table
lSqlTbl = stmt.join(joinType, joinSqlTbl, ((ElementContainerTable) joinTbl).getElementMapping(), leftTbl, null, leftTbl.getIdMapping(), null, null, true);
}
} else if (leftMmd.hasMap()) {
if (i == 0) {
// Add where clause join table (value) to outer table (id)
SQLExpression outerExpr = exprFactory.newExpression(outerSqlTbl.getSQLStatement(), outerSqlTbl, outerSqlTbl.getTable().getIdMapping());
SQLExpression joinExpr = exprFactory.newExpression(stmt, joinSqlTbl, ((MapTable) joinTbl).getValueMapping());
stmt.whereAnd(outerExpr.eq(joinExpr), false);
} else {
// Join to left table
lSqlTbl = stmt.join(joinType, joinSqlTbl, ((MapTable) joinTbl).getValueMapping(), leftTbl, null, leftTbl.getIdMapping(), null, null, true);
}
}
} else {
if (i == 0) {
// Add where clause right table to outer table
SQLExpression outerExpr = exprFactory.newExpression(outerSqlTbl.getSQLStatement(), outerSqlTbl, outerSqlTbl.getTable().getMemberMapping(leftMmd));
SQLExpression rightExpr = exprFactory.newExpression(stmt, rSqlTbl, rSqlTbl.getTable().getIdMapping());
stmt.whereAnd(outerExpr.eq(rightExpr), false);
} else {
// Join to left table
lSqlTbl = stmt.join(joinType, rSqlTbl, rSqlTbl.getTable().getIdMapping(), leftTbl, null, leftTbl.getMemberMapping(leftMmd), null, null, true);
}
}
}
rSqlTbl = lSqlTbl;
}
}
use of org.datanucleus.store.rdbms.table.JoinTable in project datanucleus-rdbms by datanucleus.
the class JoinMapStore method internalUpdate.
/**
* Method to process an "update" statement (where the key already has a value in the join table).
* @param ownerOP ObjectProvider for the owner
* @param conn The Connection
* @param batched Whether we are batching it
* @param key The key
* @param value The new value
* @param executeNow Whether to execute the statement now or wait til any batch
* @throws MappedDatastoreException Thrown if an error occurs
*/
protected void internalUpdate(ObjectProvider ownerOP, ManagedConnection conn, boolean batched, Object key, Object value, boolean executeNow) throws MappedDatastoreException {
ExecutionContext ec = ownerOP.getExecutionContext();
SQLController sqlControl = storeMgr.getSQLController();
try {
PreparedStatement ps = sqlControl.getStatementForUpdate(conn, updateStmt, false);
try {
int jdbcPosition = 1;
if (valueMapping != null) {
jdbcPosition = BackingStoreHelper.populateValueInStatement(ec, ps, value, jdbcPosition, valueMapping);
} else {
jdbcPosition = BackingStoreHelper.populateEmbeddedValueFieldsInStatement(ownerOP, value, ps, jdbcPosition, (JoinTable) mapTable, this);
}
jdbcPosition = BackingStoreHelper.populateOwnerInStatement(ownerOP, ec, ps, jdbcPosition, this);
jdbcPosition = BackingStoreHelper.populateKeyInStatement(ec, ps, key, jdbcPosition, keyMapping);
if (batched) {
ps.addBatch();
} else {
sqlControl.executeStatementUpdate(ec, conn, updateStmt, ps, true);
}
} finally {
sqlControl.closeStatement(conn, ps);
}
} catch (SQLException e) {
throw new MappedDatastoreException(getUpdateStmt(), e);
}
}
use of org.datanucleus.store.rdbms.table.JoinTable in project datanucleus-rdbms by datanucleus.
the class AbstractCollectionStore method getContainsStatementString.
private String getContainsStatementString(Object element) {
boolean elementsAreSerialised = isElementsAreSerialised();
boolean usingJoinTable = usingJoinTable();
Table selectTable = null;
JavaTypeMapping ownerMapping = null;
JavaTypeMapping elemMapping = null;
JavaTypeMapping relDiscrimMapping = null;
ComponentInfo elemInfo = null;
if (usingJoinTable) {
selectTable = this.containerTable;
ownerMapping = this.ownerMapping;
elemMapping = this.elementMapping;
relDiscrimMapping = this.relationDiscriminatorMapping;
} else {
elemInfo = getComponentInfoForElement(element);
if (elemInfo != null) {
selectTable = elemInfo.getDatastoreClass();
elemMapping = elemInfo.getDatastoreClass().getIdMapping();
if (ownerMemberMetaData.getMappedBy() != null) {
ownerMapping = selectTable.getMemberMapping(elemInfo.getAbstractClassMetaData().getMetaDataForMember(ownerMemberMetaData.getMappedBy()));
} else {
ownerMapping = elemInfo.getDatastoreClass().getExternalMapping(ownerMemberMetaData, MappingType.EXTERNAL_FK);
}
relDiscrimMapping = elemInfo.getDatastoreClass().getExternalMapping(ownerMemberMetaData, MappingType.EXTERNAL_FK_DISCRIMINATOR);
} else {
// TODO What if no suitable elementInfo found?
throw new NucleusException("Unable to locate owner mapping for backing store at " + ownerMemberMetaData.getFullFieldName());
}
}
StringBuilder stmt = new StringBuilder("SELECT ");
String containerAlias = "THIS";
String joinedElementAlias = "ELEM";
for (int i = 0; i < ownerMapping.getNumberOfDatastoreMappings(); i++) {
if (i > 0) {
stmt.append(",");
}
stmt.append(ownerMapping.getDatastoreMapping(i).getColumn().getIdentifier().toString());
}
stmt.append(" FROM ").append(selectTable.toString()).append(" ").append(containerAlias);
// TODO Add join to owner if ownerMapping is for supertable
// Add join to element table if required (only allows for 1 element table currently)
boolean joinedDiscrim = false;
// TODO Enable this code applying the discrim restriction to JoinTable cases
/*if (elementInfo != null && elementInfo[0].getTable() != containerTable && elementInfo[0].getDiscriminatorMapping() != null)
{
// Need join to the element table to restrict the discriminator
joinedDiscrim = true;
JavaTypeMapping elemIdMapping = elementInfo[0].getTable().getIdMapping();
stmt.append(" INNER JOIN ");
stmt.append(elementInfo[0].getTable().toString()).append(" ").append(joinedElementAlias).append(" ON ");
for (int i=0;i<elementMapping.getNumberOfDatastoreFields();i++)
{
if (i > 0)
{
stmt.append(" AND ");
}
stmt.append(containerAlias).append(".").append(elementMapping.getDataStoreMapping(i).getDatastoreField().getIdentifier());
stmt.append("=");
stmt.append(joinedElementAlias).append(".").append(elemIdMapping.getDataStoreMapping(0).getDatastoreField().getIdentifier());
}
}*/
stmt.append(" WHERE ");
BackingStoreHelper.appendWhereClauseForMapping(stmt, ownerMapping, containerAlias, true);
BackingStoreHelper.appendWhereClauseForElement(stmt, elemMapping, element, elementsAreSerialised, containerAlias, false);
// Needs to pass TCK M-M relationship test. see contains(ObjectProvider, Object) method also
if (!usingJoinTable && elemInfo.getDiscriminatorMapping() != null) {
// TODO What if we have the discriminator in a supertable? the mapping will be null so we don't get this clause added!
// Element table has discriminator so restrict to the element-type and subclasses
// Add WHERE for the element and each subclass type so we restrict to valid element types TODO Is the element itself included?
StringBuilder discrimStr = new StringBuilder();
Collection<String> classNames = storeMgr.getSubClassesForClass(elemInfo.getClassName(), true, clr);
classNames.add(elemInfo.getClassName());
for (String className : classNames) {
Class cls = clr.classForName(className);
if (!Modifier.isAbstract(cls.getModifiers())) {
if (discrimStr.length() > 0) {
discrimStr.append(" OR ");
}
if (joinedDiscrim) {
discrimStr.append(joinedElementAlias);
} else {
discrimStr.append(containerAlias);
}
discrimStr.append(".").append(elemInfo.getDiscriminatorMapping().getDatastoreMapping(0).getColumn().getIdentifier().toString());
discrimStr.append(" = ");
discrimStr.append(elemInfo.getDiscriminatorMapping().getDatastoreMapping(0).getUpdateInputParameter());
}
}
if (discrimStr.length() > 0) {
stmt.append(" AND (").append(discrimStr.toString()).append(")");
}
}
if (relDiscrimMapping != null) {
// Relation uses shared resource (FK, JoinTable) so restrict to this particular relation
BackingStoreHelper.appendWhereClauseForMapping(stmt, relDiscrimMapping, containerAlias, false);
}
return stmt.toString();
}
Aggregations