/// <summary> /// Creates a complete member restriction with the meaning "<paramref name="slot"/> in <paramref name="domain"/>". /// </summary> protected MemberRestriction(MemberProjectedSlot slot, Domain domain) { m_restrictedMemberSlot = slot; m_domain = domain; m_isComplete = true; Debug.Assert(m_domain.Count != 0, "If you want a boolean that evaluates to false, " + "use the ConstantBool abstraction"); }
/// <summary> /// Creates a scalar member restriction with the meaning "<paramref name="slot"/> in <paramref name="domain"/>". /// </summary> internal ScalarRestriction(MemberProjectedSlot slot, Domain domain) : base(slot, domain) { }
// effects: Creates a copy of the set "domain" internal Domain(Domain domain) { m_domain = new Set<Constant>(domain.m_domain, Constant.EqualityComparer); m_possibleValues = new Set<Constant>(domain.m_possibleValues, Constant.EqualityComparer); AssertInvariant(); }
/// <summary> /// Creates an incomplete member restriction with the meaning "<paramref name="slot"/> in <paramref name="values"/>". /// </summary> protected MemberRestriction(MemberProjectedSlot slot, IEnumerable<Constant> values) { m_restrictedMemberSlot = slot; m_domain = new Domain(values, values); }
// effects: Intersects the values in second with this domain and // returns the result private Domain Intersect(Domain second) { CheckTwoDomainInvariants(this, second); Domain result = new Domain(this); result.m_domain.Intersect(second.m_domain); return result; }
private static void CheckTwoDomainInvariants(Domain domain1, Domain domain2) { domain1.AssertInvariant(); domain2.AssertInvariant(); // The possible values must match Debug.Assert(domain1.m_possibleValues.SetEquals(domain2.m_possibleValues), "domains must be compatible"); }
// effects: Returns true iff this domain has the same values as // second. Note that this method performs a semantic check not just // an element by element check internal bool IsEqualTo(Domain second) { return m_domain.SetEquals(second.m_domain); }
// requires: domain not have any Negated constants other than NotNull // Also, cellQuery contains all final oneOfConsts or all partial oneOfConsts // cellquery must contain a whereclause of the form "True", "OneOfConst" or " // "OneOfConst AND ... AND OneOfConst" // slot must present in cellQuery and incomingDomain is the domain for it // effects: Returns the set of values that slot can take as restricted by cellQuery's whereClause private static bool TryGetDomainRestrictedByWhereClause(IEnumerable<Constant> domain, MemberProjectedSlot slot, CellQuery cellQuery, out CellConstantSet result) { var conditionsForSlot = cellQuery.GetConjunctsFromWhereClause() .Where(restriction => MemberPath.EqualityComparer.Equals(restriction.RestrictedMemberSlot.MemberPath, slot.MemberPath)) .Select(restriction => new CellConstantSet(restriction.Domain.Values, Constant.EqualityComparer)); //Debug.Assert(!conditionsForSlot.Skip(1).Any(), "More than one Clause with the same path"); if (!conditionsForSlot.Any()) { // If the slot was not mentioned in the query return the domain without restricting it result = new CellConstantSet(domain); return false; } // Now get all the possible values from domain and conditionValues CellConstantSet possibleValues = DeterminePossibleValues(conditionsForSlot.SelectMany(m => m.Select(c => c)), domain); Domain restrictedDomain = new Domain(domain, possibleValues); foreach (var conditionValues in conditionsForSlot) { // Domain derived from Edm-Type INTERSECTED with Conditions restrictedDomain = restrictedDomain.Intersect(new Domain(conditionValues, possibleValues)); } result = new CellConstantSet(restrictedDomain.Values, Constant.EqualityComparer); return !domain.SequenceEqual(result); }
internal override CqlBlock ToCqlBlock(bool[] requiredSlots, CqlIdentifiers identifiers, ref int blockAliasNum, ref List <WithRelationship> withRelationships) { // Get the projected slots and the boolean expressions int totalSlots = requiredSlots.Length; CellQuery cellQuery = LeftCellWrapper.RightCellQuery; SlotInfo[] projectedSlots = new SlotInfo[totalSlots]; Debug.Assert(cellQuery.NumProjectedSlots + cellQuery.NumBoolVars == totalSlots, "Wrong number of projected slots in node"); Debug.Assert(cellQuery.NumProjectedSlots == ProjectedSlotMap.Count, "Different number of slots in cell query and what we have mappings for"); // Add the regular fields for (int i = 0; i < cellQuery.NumProjectedSlots; i++) { ProjectedSlot slot = cellQuery.ProjectedSlotAt(i); // If the slot is not null, we will project it // For extents, we say that all requiredlots are the only the // ones that are CLR non-null. Recall that "real" nulls are // handled by having a CellConstant.Null in ConstantSlot if (requiredSlots[i] && slot == null) { MemberPath memberPath = ProjectedSlotMap[i]; ConstantProjectedSlot defaultValue = new ConstantProjectedSlot(Domain.GetDefaultValueForMemberPath(memberPath, GetLeaves(), ViewgenContext.Config), memberPath); cellQuery.FixMissingSlotAsDefaultConstant(i, defaultValue); slot = defaultValue; } SlotInfo slotInfo = new SlotInfo(requiredSlots[i], slot != null, slot, ProjectedSlotMap[i]); projectedSlots[i] = slotInfo; } // Add the boolean fields for (int boolNum = 0; boolNum < cellQuery.NumBoolVars; boolNum++) { BoolExpression expr = cellQuery.GetBoolVar(boolNum); BooleanProjectedSlot boolSlot; if (expr != null) { boolSlot = new BooleanProjectedSlot(expr, identifiers, boolNum); } else { boolSlot = new BooleanProjectedSlot(BoolExpression.False, identifiers, boolNum); } int slotIndex = BoolIndexToSlot(boolNum); SlotInfo slotInfo = new SlotInfo(requiredSlots[slotIndex], expr != null, boolSlot, null); projectedSlots[slotIndex] = slotInfo; } // See if we are generating a query view and whether there are any colocated foreign keys for which // we have to add With statements. IEnumerable <SlotInfo> totalProjectedSlots = projectedSlots; if ((cellQuery.Extent.EntityContainer.DataSpace == DataSpace.SSpace) && (this.m_cellWrapper.LeftExtent.BuiltInTypeKind == BuiltInTypeKind.EntitySet)) { IEnumerable <StorageAssociationSetMapping> associationSetMaps = this.ViewgenContext.EntityContainerMapping.GetRelationshipSetMappingsFor(this.m_cellWrapper.LeftExtent, cellQuery.Extent); List <SlotInfo> foreignKeySlots = new List <SlotInfo>(); foreach (StorageAssociationSetMapping colocatedAssociationSetMap in associationSetMaps) { WithRelationship withRelationship; if (TryGetWithRelationship(colocatedAssociationSetMap, this.m_cellWrapper.LeftExtent, cellQuery.SourceExtentMemberPath, ref foreignKeySlots, out withRelationship)) { withRelationships.Add(withRelationship); totalProjectedSlots = projectedSlots.Concat(foreignKeySlots); } } } ExtentCqlBlock result = new ExtentCqlBlock(cellQuery.Extent, cellQuery.SelectDistinctFlag, totalProjectedSlots.ToArray(), cellQuery.WhereClause, identifiers, ++blockAliasNum); return(result); }
// determine the domain query, i.e., the query that returns all keys of the extent to be populated internal FragmentQuery GetDomainQuery(IEnumerable<FragmentQuery> fragmentQueries, EdmType generatedType) { BoolExpression domainQueryCondition = null; if (_context.ViewTarget == ViewTarget.QueryView) { if (generatedType == null) { // domainQuery for entire extent: True domainQueryCondition = BoolExpression.True; } else // domainQuery for specific type: WHERE type(path) IS OF (Type) { //If Mode is OFTypeOnlyViews then don't get subtypes IEnumerable<EdmType> derivedTypes; if (_typesGenerationMode == ViewGenMode.OfTypeOnlyViews) { Debug.Assert(!Helper.IsRefType(_generatedType)); var type = new HashSet<EdmType>(); type.Add(_generatedType); derivedTypes = type; } else { derivedTypes = MetadataHelper.GetTypeAndSubtypesOf( generatedType, _context.EdmItemCollection, false /* don't include abstract types */); } var typeDomain = new Domain(GetTypeConstants(derivedTypes), _domainMap.GetDomain(_extentPath)); domainQueryCondition = BoolExpression.CreateLiteral(new TypeRestriction(new MemberProjectedSlot(_extentPath), typeDomain), _domainMap); } return FragmentQuery.Create(_keyAttributes, domainQueryCondition); } else // for update views, domain query = exposed tiles { var whereClauses = from fragmentQuery in fragmentQueries select fragmentQuery.Condition; var exposedRegionCondition = BoolExpression.CreateOr(whereClauses.ToArray()); return FragmentQuery.Create(_keyAttributes, exposedRegionCondition); } }
// effects: Creates a copy of the set "domain" internal Domain(Domain domain) { m_domain = new Set <Constant>(domain.m_domain, Constant.EqualityComparer); m_possibleValues = new Set <Constant>(domain.m_possibleValues, Constant.EqualityComparer); AssertInvariant(); }
// effects: Returns true iff this domain has the same values as // second. Note that this method performs a semantic check not just // an element by element check internal bool IsEqualTo(Domain second) { return(m_domain.SetEquals(second.m_domain)); }
// effects: Creates a map with all the condition member constants // from extentCells. viewtarget determines whether the view is an // update or query view internal MemberDomainMap(ViewTarget viewTarget, bool isValidationEnabled, IEnumerable <Cell> extentCells, EdmItemCollection edmItemCollection, ConfigViewGenerator config, Dictionary <EntityType, Set <EntityType> > inheritanceGraph) { m_conditionDomainMap = new Dictionary <MemberPath, CellConstantSet>(MemberPath.EqualityComparer); m_edmItemCollection = edmItemCollection; Dictionary <MemberPath, CellConstantSet> domainMap = null; if (viewTarget == ViewTarget.UpdateView) { domainMap = Domain.ComputeConstantDomainSetsForSlotsInUpdateViews(extentCells, m_edmItemCollection); } else { domainMap = Domain.ComputeConstantDomainSetsForSlotsInQueryViews(extentCells, m_edmItemCollection, isValidationEnabled); } foreach (Cell cell in extentCells) { CellQuery cellQuery = cell.GetLeftQuery(viewTarget); // Get the atoms from cellQuery and only keep the ones that // are condition members foreach (MemberRestriction condition in cellQuery.GetConjunctsFromWhereClause()) { // Note: TypeConditions are created using OneOfTypeConst and // scalars are created using OneOfScalarConst MemberPath memberPath = condition.RestrictedMemberSlot.MemberPath; Debug.Assert(condition is ScalarRestriction || condition is TypeRestriction, "Unexpected restriction"); // Take the narrowed domain from domainMap, if any CellConstantSet domainValues; if (!domainMap.TryGetValue(memberPath, out domainValues)) { domainValues = Domain.DeriveDomainFromMemberPath(memberPath, edmItemCollection, isValidationEnabled); } //Don't count conditions that are satisfied through IsNull=false if (!domainValues.Contains(Constant.Null)) { //multiple values of condition represent disjunction in conditions (not currently supported) // if there is any condition constant that is NotNull if (condition.Domain.Values.All(conditionConstant => (conditionConstant.Equals(Constant.NotNull)))) { continue; } //else there is atleast one condition value that is allowed, continue view generation } //------------------------------------------ //| Nullable | IsNull | Test case | //| T | T | T | //| T | F | T | //| F | T | F | //| F | F | T | //------------------------------------------ //IsNull condition on a member that is non nullable is an invalid condition if (domainValues.Count <= 0 || (!domainValues.Contains(Constant.Null) && condition.Domain.Values.Contains(Constant.Null))) { string message = System.Data.Entity.Strings.ViewGen_InvalidCondition(memberPath.PathToString(false)); ErrorLog.Record record = new ErrorLog.Record(true, ViewGenErrorCode.InvalidCondition, message, cell, String.Empty); ExceptionHelpers.ThrowMappingException(record, config); } if (memberPath.IsAlwaysDefined(inheritanceGraph) == false) { domainValues.Add(Constant.Undefined); } AddToDomainMap(memberPath, domainValues); } } // Fill up the domains for the remaining slots as well m_nonConditionDomainMap = new Dictionary <MemberPath, CellConstantSet>(MemberPath.EqualityComparer); foreach (Cell cell in extentCells) { CellQuery cellQuery = cell.GetLeftQuery(viewTarget); // Get the atoms from cellQuery and only keep the ones that // are condition members foreach (MemberProjectedSlot slot in cellQuery.GetAllQuerySlots()) { MemberPath member = slot.MemberPath; if (m_conditionDomainMap.ContainsKey(member) == false && m_nonConditionDomainMap.ContainsKey(member) == false) { CellConstantSet memberSet = Domain.DeriveDomainFromMemberPath(member, m_edmItemCollection, true /* Regardless of validation, leave the domain unbounded because this is not a condition member */); if (member.IsAlwaysDefined(inheritanceGraph) == false) { // nonConditionMember may belong to subclass memberSet.Add(Constant.Undefined); } memberSet = Domain.ExpandNegationsInDomain(memberSet, memberSet); m_nonConditionDomainMap.Add(member, new CellConstantSetInfo(memberSet, slot)); } } } }
// effects: Generates a SlotInfo object for a slot of a join node. It // uses the type of the join operation (opType), whether the slot is // required by the parent or not (isRequiredSlot), the children of // this node (children) and the number of the slotNum private SlotInfo GetJoinSlotInfo(CellTreeOpType opType, bool isRequiredSlot, List <CqlBlock> children, int slotNum, CqlIdentifiers identifiers) { if (false == isRequiredSlot) { // The slot will not be used. So we can set the projected slot to be null SlotInfo unrequiredSlotInfo = new SlotInfo(false, false, null, GetMemberPath(slotNum)); return(unrequiredSlotInfo); } // For a required slot, determine the child who is contributing to this value int childDefiningSlot = -1; CaseStatement caseForOuterJoins = null; for (int childNum = 0; childNum < children.Count; childNum++) { CqlBlock child = children[childNum]; if (false == child.IsProjected(slotNum)) { continue; } // For keys, we can pick any child block. So the first // one that we find is fine as well if (IsKeySlot(slotNum)) { childDefiningSlot = childNum; break; } else if (opType == CellTreeOpType.IJ) { // For Inner Joins, most of the time, the entries will be // the same in all the children. However, in some cases, // we will end up with NULL in one child and an actual // value in another -- we should pick up the actual value in that case childDefiningSlot = GetInnerJoinChildForSlot(children, slotNum); break; } else { // For LOJs, we generate a case statement if more than // one child generates the value - until then we do not // create the caseForOuterJoins object if (childDefiningSlot != -1) { // We really need a case statement now // We have the value being generated by another child // We need to fetch the variable from the appropriate child Debug.Assert(false == IsBoolSlot(slotNum), "Boolean slots cannot come from two children"); if (caseForOuterJoins == null) { MemberPath outputMember = GetMemberPath(slotNum); caseForOuterJoins = new CaseStatement(outputMember); // Add the child that we had not added in the first shot AddCaseForOuterJoins(caseForOuterJoins, children[childDefiningSlot], slotNum, identifiers); } AddCaseForOuterJoins(caseForOuterJoins, child, slotNum, identifiers); } childDefiningSlot = childNum; } } MemberPath memberPath = GetMemberPath(slotNum); ProjectedSlot slot = null; // Generate the slot value -- case statement slot, or a qualified slot or null or false. // If case statement slot has nothing, treat it as null/empty. if (caseForOuterJoins != null && (caseForOuterJoins.Clauses.Count > 0 || caseForOuterJoins.ElseValue != null)) { caseForOuterJoins.Simplify(); slot = new CaseStatementProjectedSlot(caseForOuterJoins, null); } else if (childDefiningSlot >= 0) { slot = children[childDefiningSlot].QualifySlotWithBlockAlias(slotNum); } else { // need to produce output slot, but don't have a value // output NULL for fields or False for bools if (IsBoolSlot(slotNum)) { slot = new BooleanProjectedSlot(BoolExpression.False, identifiers, SlotToBoolIndex(slotNum)); } else { slot = new ConstantProjectedSlot(Domain.GetDefaultValueForMemberPath(memberPath, GetLeaves(), ViewgenContext.Config), memberPath); } } // We need to ensure that _from variables are never null since // view generation uses 2-valued boolean logic. // They can become null in outer joins. We compensate for it by // adding AND NOT NULL condition on boolean slots coming from outer joins. bool enforceNotNull = IsBoolSlot(slotNum) && ((opType == CellTreeOpType.LOJ && childDefiningSlot > 0) || opType == CellTreeOpType.FOJ); // We set isProjected to be true since we have come up with some value for it SlotInfo slotInfo = new SlotInfo(true, true, slot, memberPath, enforceNotNull); return(slotInfo); }