public void prepareUpdateExpressionWithRow(NSDictionary row, EOQualifier qualifier) { EOAttribute attribute; Object value; for (Enumeration enumeration = row.keyEnumerator(); enumeration.hasMoreElements(); addUpdateListAttribute(attribute, value)) { String attributeName = (String) enumeration.nextElement(); attribute = this.entity().anyAttributeNamed(attributeName); if (attribute == null) throw new IllegalStateException( "prepareUpdateExpressionWithRow: row argument contains key '" + attributeName + "' which does not have corresponding attribute on entity '" + this.entity().name() + "'"); value = row.objectForKey(attributeName); } _whereClauseString = EOQualifierSQLGeneration.Support._sqlStringForSQLExpression(qualifier, this); String tableList = tableListWithRootEntity(_rootEntityForExpression()); _statement = assembleUpdateStatementWithRow( row, qualifier, tableList, new String(_listString), _whereClauseString); }
// ENHANCEME: This should support restrictive qualifiers on the root entity @Override public EOQualifier schemaBasedQualifierWithRootEntity( EOQualifier eoqualifier, EOEntity eoentity) { EOQualifier result = null; EOKeyValueQualifier qualifier = (EOKeyValueQualifier) eoqualifier; String key = qualifier.key(); if (qualifier.selector().name().equals(MatchesAllInArraySelectorName)) { EOQualifierSQLGeneration.Support support = EOQualifierSQLGeneration.Support.supportForClass(ERXToManyQualifier.class); NSArray array = (NSArray) qualifier.value(); ERXToManyQualifier q = new ERXToManyQualifier(key, array, array.count()); result = support.schemaBasedQualifierWithRootEntity(q, eoentity); return result; } return (EOQualifier) eoqualifier.clone(); }
@Override public EOQualifier qualifierMigratedFromEntityRelationshipPath( EOQualifier eoqualifier, EOEntity eoentity, String relationshipPath) { ERXToManyQualifier qualifier = (ERXToManyQualifier) eoqualifier; String newPath = EOQualifierSQLGeneration.Support._translateKeyAcrossRelationshipPath( qualifier.key(), relationshipPath, eoentity); return new ERXToManyQualifier(newPath, qualifier.elements(), qualifier.minCount()); }
/** Register SQL generation support for the qualifier. */ static { EOQualifierSQLGeneration.Support.setSupportForClass( new ExistsQualifierSQLGenerationSupport(), ERXExistsQualifier.class); }
/** * Generates the EXISTS SQL string for the given SQL expression. The bulk of the logic for * generating the sub-query is in this method. * * @param qualifier for which to generate the SQL * @param expression to use during SQL generation * @return SQL string for the current sub-query */ public String sqlStringForSQLExpression(EOQualifier qualifier, EOSQLExpression expression) { if (null == qualifier || null == expression) { return null; } ERXExistsQualifier existsQualifier = (ERXExistsQualifier) qualifier; EOQualifier subqualifier = existsQualifier.subqualifier(); String baseKeyPath = existsQualifier.baseKeyPath(); EOEntity baseEntity = expression.entity(); EORelationship relationship = null; // Walk the key path to the last entity. if (baseKeyPath != null) { for (Enumeration pathEnum = NSArray.componentsSeparatedByString(baseKeyPath, ".").objectEnumerator(); pathEnum.hasMoreElements(); ) { String path = (String) pathEnum.nextElement(); if (null == relationship) { relationship = baseEntity.anyRelationshipNamed(path); } else { relationship = relationship.destinationEntity().anyRelationshipNamed(path); } } } EOEntity srcEntity = relationship != null ? relationship.entity() : baseEntity; EOEntity destEntity = relationship != null ? relationship.destinationEntity() : baseEntity; // We need to do a bunch of hand-waiving to get the right table aliases for the table used in // the exists // subquery and for the join clause back to the source table. String sourceTableAlias = "t0"; // The alias for the the source table of the baseKeyPath from the main query. String destTableAlias; // The alias for the table used in the subquery. if (!srcEntity.equals(baseEntity)) { // The exists clause is applied to the different table. String sourceKeyPath = ERXStringUtilities.keyPathWithoutLastProperty(baseKeyPath); sqlStringForAttributeNamedInExpression(sourceKeyPath, expression); sqlStringForAttributeNamedInExpression(baseKeyPath, expression); sourceTableAlias = (String) expression.aliasesByRelationshipPath().valueForKey(sourceKeyPath); destTableAlias = (String) expression.aliasesByRelationshipPath().valueForKey(baseKeyPath); if (null == destTableAlias) { destTableAlias = "t" + (expression.aliasesByRelationshipPath().count()); // The first entry = "t0". expression.aliasesByRelationshipPath().takeValueForKey(destTableAlias, baseKeyPath); } } else { // The exists clause is applied to the base table. destTableAlias = "t" + expression.aliasesByRelationshipPath().count(); // Probably "t1" } EOAttribute sourceKeyAttribute = srcEntity.primaryKeyAttributes().lastObject(); String sourceKey = expression.sqlStringForAttribute(sourceKeyAttribute); EOAttribute destKeyAttribute = relationship.destinationAttributes().lastObject(); String destKey = expression.sqlStringForAttribute(destKeyAttribute); EOQualifier qual = EOQualifierSQLGeneration.Support._schemaBasedQualifierWithRootEntity( subqualifier, destEntity); EOFetchSpecification fetchSpecification = new EOFetchSpecification(destEntity.name(), qual, null, false, true, null); EODatabaseContext context = EODatabaseContext.registeredDatabaseContextForModel( destEntity.model(), EOObjectStoreCoordinator.defaultCoordinator()); EOSQLExpressionFactory factory = context.database().adaptor().expressionFactory(); EOSQLExpression subExpression = factory.expressionForEntity(destEntity); subExpression.aliasesByRelationshipPath().setObjectForKey(destTableAlias, ""); subExpression.setUseAliases(true); subExpression.prepareSelectExpressionWithAttributes( destEntity.primaryKeyAttributes(), false, fetchSpecification); for (Enumeration bindEnumeration = subExpression.bindVariableDictionaries().objectEnumerator(); bindEnumeration.hasMoreElements(); ) { expression.addBindVariableDictionary((NSDictionary) bindEnumeration.nextElement()); } StringBuffer sb = new StringBuffer(); sb.append(" EXISTS ( "); sb.append( ERXStringUtilities.replaceStringByStringInString( "t0.", destTableAlias + ".", subExpression.statement())); sb.append(" AND "); sb.append( ERXStringUtilities.replaceStringByStringInString("t0.", destTableAlias + ".", destKey)); sb.append(" = "); sb.append( ERXStringUtilities.replaceStringByStringInString( "t0.", sourceTableAlias + ".", sourceKey)); sb.append(" ) "); return sb.toString(); }
/** * Generates the sql string for the given sql expression. Bulk of the logic for generating the * sub-query is in this method. * * @param e a given sql expression * @return sql string for the current sub-query. */ public String sqlStringForSQLExpression(EOSQLExpression e) { StringBuffer sb = new StringBuffer(); if (attributeName != null) sb.append(e.sqlStringForAttributeNamed(attributeName)); else { EOAttribute pk = (EOAttribute) e.entity().primaryKeyAttributes().lastObject(); sb.append(e.sqlStringForAttribute(pk)); } sb.append(" IN ( "); EOEntity entity = entityName == null ? e.entity() : e.entity().model().modelGroup().entityNamed(entityName); EOFetchSpecification fs = new EOFetchSpecification(entity.name(), qualifier, null, false, true, null); if (qualifier != null) { qualifier = EOQualifierSQLGeneration.Support._schemaBasedQualifierWithRootEntity(qualifier, entity); } if (qualifier != fs.qualifier()) { fs.setQualifier(qualifier); } // ASSUME: This makes a few assumptions, if anyone can figure out a fool // proof way that would be nice to get the model // Note you can't use: // EOAdaptor.adaptorWithModel(e.entity().model()).expressionFactory(); // as this creates a // EODatabaseContext context = EODatabaseContext.registeredDatabaseContextForModel( entity.model(), EOObjectStoreCoordinator.defaultCoordinator()); EOSQLExpressionFactory factory = context.database().adaptor().expressionFactory(); NSArray subAttributes = destinationAttName != null ? new NSArray(entity.attributeNamed(destinationAttName)) : entity.primaryKeyAttributes(); EOSQLExpression subExpression = factory.expressionForEntity(entity); // Arroz: Having this table identifier replacement causes serious // problems if you have more than a table being processed in the subquery. Disabling // it will apparently not cause problems, because t0 inside the subquery is not // the same t0 outside it. // subExpression.aliasesByRelationshipPath().setObjectForKey("t1", ""); subExpression.setUseAliases(true); subExpression.prepareSelectExpressionWithAttributes(subAttributes, false, fs); // EOSQLExpression // expression=factory.selectStatementForAttributes(entity.primaryKeyAttributes(), // false, fs, entity); for (Enumeration bindEnumeration = subExpression.bindVariableDictionaries().objectEnumerator(); bindEnumeration.hasMoreElements(); ) { e.addBindVariableDictionary((NSDictionary) bindEnumeration.nextElement()); } // sb.append(ERXStringUtilities.replaceStringByStringInString("t0.", // "t1.", subExpression.statement())); sb.append(subExpression.statement()); sb.append(" ) "); return sb.toString(); }
/** register SQL generation support for the qualifier */ static { EOQualifierSQLGeneration.Support.setSupportForClass( new ToManyQualifierSQLGenerationSupport(), ERXToManyQualifier.class); }