Esempio n. 1
0
        internal QueryRewriter(EdmType generatedType, ViewgenContext context, ViewGenMode typesGenerationMode)
        {
            Debug.Assert(typesGenerationMode != ViewGenMode.GenerateAllViews);

            _typesGenerationMode = typesGenerationMode;
            _context = context;
            _generatedType = generatedType;
            _domainMap = context.MemberMaps.LeftDomainMap;
            _config = context.Config;
            _identifiers = context.CqlIdentifiers;
            _qp = new RewritingProcessor<Tile<FragmentQuery>>(new DefaultTileProcessor<FragmentQuery>(context.LeftFragmentQP));
            _extentPath = new MemberPath(context.Extent);
            _keyAttributes = new List<MemberPath>(MemberPath.GetKeyMembers(context.Extent, _domainMap));

            // populate _fragmentQueries and _views
            foreach (var leftCellWrapper in _context.AllWrappersForExtent)
            {
                var query = leftCellWrapper.FragmentQuery;
                Tile<FragmentQuery> tile = CreateTile(query);
                _fragmentQueries.Add(query);
                _views.Add(tile);
            }
            Debug.Assert(_views.Count > 0);

            AdjustMemberDomainsForUpdateViews();

            // must be done after adjusting domains
            _domainQuery = GetDomainQuery(FragmentQueries, generatedType);

            _usedViews = new HashSet<FragmentQuery>();
        }
Esempio n. 2
0
 // <summary>
 // Initializes a <see cref="CqlBlock" /> with the SELECT (<paramref name="slotInfos" />), FROM (
 // <paramref
 //     name="children" />
 // ),
 // WHERE (<paramref name="whereClause" />), AS (<paramref name="blockAliasNum" />).
 // </summary>
 protected CqlBlock(
     SlotInfo[] slotInfos, List<CqlBlock> children, BoolExpression whereClause, CqlIdentifiers identifiers, int blockAliasNum)
 {
     m_slots = new ReadOnlyCollection<SlotInfo>(slotInfos);
     m_children = new ReadOnlyCollection<CqlBlock>(children);
     m_whereClause = whereClause;
     m_blockAlias = identifiers.GetBlockAlias(blockAliasNum);
 }
        /// <summary>
        ///     Creates a boolean slot for expression that comes from originalCellNum, i.e., 
        ///     the value of the slot is <paramref name="expr" /> and the name is "_from{<paramref name="originalCellNum" />}", e.g., _from2
        /// </summary>
        internal BooleanProjectedSlot(BoolExpression expr, CqlIdentifiers identifiers, int originalCellNum)
        {
            m_expr = expr;
            m_originalCell = new CellIdBoolean(identifiers, originalCellNum);

            Debug.Assert(
                !(expr.AsLiteral is CellIdBoolean) ||
                BoolLiteral.EqualityComparer.Equals(expr.AsLiteral, m_originalCell), "Cellid boolean for the slot and cell number disagree");
        }
 /// <summary>
 ///     Creates a join block (type given by <paramref name="opType" />) with SELECT (<paramref name="slotInfos" />), FROM (
 ///     <paramref
 ///         name="children" />
 ///     ),
 ///     ON (<paramref name="onClauses" /> - one for each child except 0th), WHERE (true), AS (
 ///     <paramref
 ///         name="blockAliasNum" />
 ///     ).
 /// </summary>
 internal JoinCqlBlock(
     CellTreeOpType opType,
     SlotInfo[] slotInfos,
     List<CqlBlock> children,
     List<OnClause> onClauses,
     CqlIdentifiers identifiers,
     int blockAliasNum)
     : base(slotInfos, children, BoolExpression.True, identifiers, blockAliasNum)
 {
     m_opType = opType;
     m_onClauses = onClauses;
 }
Esempio n. 5
0
 // <summary>
 // Creates an cql block representing the <paramref name="extent" /> (the FROM part).
 // SELECT is given by <paramref name="slots" />, WHERE by <paramref name="whereClause" /> and AS by
 // <paramref
 //     name="blockAliasNum" />
 // .
 // </summary>
 internal ExtentCqlBlock(
     EntitySetBase extent,
     CellQuery.SelectDistinct selectDistinct,
     SlotInfo[] slots,
     BoolExpression whereClause,
     CqlIdentifiers identifiers,
     int blockAliasNum)
     : base(slots, _emptyChildren, whereClause, identifiers, blockAliasNum)
 {
     m_extent = extent;
     m_nodeTableAlias = identifiers.GetBlockAlias();
     m_selectDistinct = selectDistinct;
 }
 /// <summary>
 ///     Given the generated <paramref name="view" />, the <paramref name="caseStatements" /> for the multiconstant fields,
 ///     the <paramref name="projectedSlotMap" /> that maps different paths of the entityset (for which the view is being generated) to slot indexes in the view,
 ///     creates an object that is capable of generating the Cql for <paramref name="view" />.
 /// </summary>
 internal CqlGenerator(
     CellTreeNode view,
     Dictionary<MemberPath,
         CaseStatement> caseStatements,
     CqlIdentifiers identifiers,
     MemberProjectionIndex projectedSlotMap,
     int numCellsInView,
     BoolExpression topLevelWhereClause,
     StorageMappingItemCollection mappingItemCollection)
 {
     m_view = view;
     m_caseStatements = caseStatements;
     m_projectedSlotMap = projectedSlotMap;
     m_numBools = numCellsInView; // We have that many booleans
     m_topLevelWhereClause = topLevelWhereClause;
     m_identifiers = identifiers;
     m_mappingItemCollection = mappingItemCollection;
 }
 internal abstract CqlBlock ToCqlBlock(
     bool[] requiredSlots,
     CqlIdentifiers identifiers,
     ref int blockAliasNum,
     ref List <WithRelationship> withRelationships);
Esempio n. 8
0
        internal ViewgenContext(
            ViewTarget viewTarget, EntitySetBase extent, IList<Cell> extentCells,
            CqlIdentifiers identifiers, ConfigViewGenerator config, MemberDomainMap queryDomainMap,
            MemberDomainMap updateDomainMap, EntityContainerMapping entityContainerMapping)
        {
            foreach (var cell in extentCells)
            {
                Debug.Assert(extent.Equals(cell.GetLeftQuery(viewTarget).Extent));
                Debug.Assert(cell.CQuery.NumProjectedSlots == cell.SQuery.NumProjectedSlots);
            }

            m_extent = extent;
            m_viewTarget = viewTarget;
            m_config = config;
            m_edmItemCollection = entityContainerMapping.StorageMappingItemCollection.EdmItemCollection;
            m_entityContainerMapping = entityContainerMapping;
            m_identifiers = identifiers;

            // create a copy of updateDomainMap so generation of query views later on is not affected
            // it is modified in QueryRewriter.AdjustMemberDomainsForUpdateViews
            updateDomainMap = updateDomainMap.MakeCopy();

            // Create a signature generator that handles all the
            // multiconstant work and generating the signatures
            var domainMap = viewTarget == ViewTarget.QueryView ? queryDomainMap : updateDomainMap;

            m_memberMaps = new MemberMaps(
                viewTarget, MemberProjectionIndex.Create(extent, m_edmItemCollection), queryDomainMap, updateDomainMap);

            // Create left fragment KB: includes constraints for the extent to be constructed
            var leftKB = new FragmentQueryKBChaseSupport();
            leftKB.CreateVariableConstraints(extent, domainMap, m_edmItemCollection);
            m_leftFragmentQP = new FragmentQueryProcessor(leftKB);
            m_rewritingCache = new Dictionary<FragmentQuery, Tile<FragmentQuery>>(
                FragmentQuery.GetEqualityComparer(m_leftFragmentQP));

            // Now using the signatures, create new cells such that
            // "extent's" query (C or S) is described in terms of multiconstants
            if (!CreateLeftCellWrappers(extentCells, viewTarget))
            {
                return;
            }

            // Create right fragment KB: includes constraints for all extents and association roles of right queries
            var rightKB = new FragmentQueryKBChaseSupport();
            var rightDomainMap = viewTarget == ViewTarget.QueryView ? updateDomainMap : queryDomainMap;
            foreach (var leftCellWrapper in m_cellWrappers)
            {
                var rightExtent = leftCellWrapper.RightExtent;
                rightKB.CreateVariableConstraints(rightExtent, rightDomainMap, m_edmItemCollection);
                rightKB.CreateAssociationConstraints(rightExtent, rightDomainMap, m_edmItemCollection);
            }

            if (m_viewTarget == ViewTarget.UpdateView)
            {
                CreateConstraintsForForeignKeyAssociationsAffectingThisWrapper(rightKB, rightDomainMap);
            }

            m_rightFragmentQP = new FragmentQueryProcessor(rightKB);

            // Check for concurrency control tokens
            if (m_viewTarget == ViewTarget.QueryView)
            {
                CheckConcurrencyControlTokens();
            }
            // For backward compatibility -
            // order wrappers by increasing domain size, decreasing number of attributes
            m_cellWrappers.Sort(LeftCellWrapper.Comparer);
        }
Esempio n. 9
0
 // effects: Determines all the identifiers used in this and adds them to identifiers
 internal void GetIdentifiers(CqlIdentifiers identifiers)
 {
     m_cQuery.GetIdentifiers(identifiers);
     m_sQuery.GetIdentifiers(identifiers);
 }
Esempio n. 10
0
        // effects: Generates a view for an extent "extent" that belongs to
        // schema "schema". extentCells are the cells for this extent.
        // Adds the view corrsponding to the extent to "views"
        private QueryRewriter GenerateDirectionalViewsForExtent(
            ViewTarget viewTarget, EntitySetBase extent, CqlIdentifiers identifiers, ViewSet views)
        {
            // First normalize the cells in terms of multiconstants, etc
            // and then generate the view for the extent
            var context = CreateViewgenContext(extent, viewTarget, identifiers);
            QueryRewriter queryRewriter = null;

            if (m_config.GenerateViewsForEachType)
            {
                // generate views for each OFTYPE(Extent, Type) combination
                foreach (
                    var type in
                        MetadataHelper.GetTypeAndSubtypesOf(
                            extent.ElementType, m_entityContainerMapping.StorageMappingItemCollection.EdmItemCollection, false
                            /*includeAbstractTypes*/))
                {
                    if (m_config.IsViewTracing
                        && false == type.Equals(extent.ElementType))
                    {
                        Helpers.FormatTraceLine("CQL View for {0} and type {1}", extent.Name, type.Name);
                    }
                    queryRewriter = GenerateViewsForExtentAndType(type, context, identifiers, views, ViewGenMode.OfTypeViews);
                }
            }
            else
            {
                // generate the view for Extent only
                queryRewriter = GenerateViewsForExtentAndType(extent.ElementType, context, identifiers, views, ViewGenMode.OfTypeViews);
            }
            if (viewTarget == ViewTarget.QueryView)
            {
                m_config.SetTimeForFinishedActivity(PerfType.QueryViews);
            }
            else
            {
                m_config.SetTimeForFinishedActivity(PerfType.UpdateViews);
            }

            // cache this rewriter (and context inside it) for future use in FK checking
            m_queryRewriterCache[extent] = queryRewriter;
            return queryRewriter;
        }
Esempio n. 11
0
        // requires: node corresponds to an IJ, LOJ, FOJ node
        // effects: Given a union node and the slots required by the parent,
        // generates a CqlBlock for the subtree rooted at node
        private CqlBlock JoinToCqlBlock(
            bool[] requiredSlots, CqlIdentifiers identifiers, ref int blockAliasNum, ref List <WithRelationship> withRelationships)
        {
            var totalSlots = requiredSlots.Length;

            Debug.Assert(
                OpType == CellTreeOpType.IJ ||
                OpType == CellTreeOpType.LOJ ||
                OpType == CellTreeOpType.FOJ, "Only these join operations handled");

            var children             = new List <CqlBlock>();
            var additionalChildSlots = new List <Tuple <QualifiedSlot, MemberPath> >();

            // First get the children nodes (FROM part)
            foreach (var child in Children)
            {
                // Determine the slots that are projected by this child.
                // These are the required slots as well - unlike Union, we do not need the child to project any extra nulls.
                var childProjectedSlots = child.GetProjectedSlots();
                AndWith(childProjectedSlots, requiredSlots);
                var childBlock = child.ToCqlBlock(childProjectedSlots, identifiers, ref blockAliasNum, ref withRelationships);
                children.Add(childBlock);
                for (var qualifiedSlotNumber = childProjectedSlots.Length;
                     qualifiedSlotNumber < childBlock.Slots.Count;
                     qualifiedSlotNumber++)
                {
                    additionalChildSlots.Add(
                        Tuple.Create(childBlock.QualifySlotWithBlockAlias(qualifiedSlotNumber), childBlock.MemberPath(qualifiedSlotNumber)));
                }
                Debug.Assert(
                    totalSlots == child.NumBoolSlots + child.NumProjectedSlots,
                    "Number of required slots is different from what each node in the tree has?");
            }

            // Now get the slots that are projected out by this node (SELECT part)
            var slotInfos = new SlotInfo[totalSlots + additionalChildSlots.Count];

            for (var slotNum = 0; slotNum < totalSlots; slotNum++)
            {
                // Note: this call could create a CaseStatementSlot (i.e., slotInfo.SlotValue is CaseStatementSlot)
                // which uses "from" booleans that need to be projected by children
                var slotInfo = GetJoinSlotInfo(OpType, requiredSlots[slotNum], children, slotNum, identifiers);
                slotInfos[slotNum] = slotInfo;
            }

            for (int i = 0, slotNum = totalSlots; slotNum < totalSlots + additionalChildSlots.Count; slotNum++, i++)
            {
                slotInfos[slotNum] = new SlotInfo(true, true, additionalChildSlots[i].Item1, additionalChildSlots[i].Item2);
            }

            // Generate the ON conditions: For each child, generate an ON
            // clause with the 0th child on the key fields
            var onClauses = new List <JoinCqlBlock.OnClause>();

            for (var i = 1; i < children.Count; i++)
            {
                var child    = children[i];
                var onClause = new JoinCqlBlock.OnClause();
                foreach (var keySlotNum in KeySlots)
                {
                    if (ViewgenContext.Config.IsValidationEnabled)
                    {
                        Debug.Assert(children[0].IsProjected(keySlotNum), "Key is not in 0th child");
                        Debug.Assert(child.IsProjected(keySlotNum), "Key is not in child");
                    }
                    else
                    {
                        if (!child.IsProjected(keySlotNum) ||
                            !children[0].IsProjected(keySlotNum))
                        {
                            var errorLog = new ErrorLog();
                            errorLog.AddEntry(
                                new ErrorLog.Record(
                                    ViewGenErrorCode.NoJoinKeyOrFKProvidedInMapping,
                                    Strings.Viewgen_NoJoinKeyOrFK, ViewgenContext.AllWrappersForExtent, String.Empty));
                            ExceptionHelpers.ThrowMappingException(errorLog, ViewgenContext.Config);
                        }
                    }
                    var firstSlot    = children[0].QualifySlotWithBlockAlias(keySlotNum);
                    var secondSlot   = child.QualifySlotWithBlockAlias(keySlotNum);
                    var outputMember = slotInfos[keySlotNum].OutputMember;
                    onClause.Add(firstSlot, outputMember, secondSlot, outputMember);
                }
                onClauses.Add(onClause);
            }

            CqlBlock result = new JoinCqlBlock(OpType, slotInfos, children, onClauses, identifiers, ++blockAliasNum);

            return(result);
        }
Esempio n. 12
0
        // effects: Generates views for the particular cellgroup in this. Returns an
        // error log describing the errors that were encountered (if none
        // were encountered, the ErrorLog.Count is 0). Places the generated
        // views in result
        internal ErrorLog GenerateAllBidirectionalViews(ViewSet views, CqlIdentifiers identifiers)
        {
            // Allow missing attributes for now to make entity splitting run through
            // we cannot do this for query views in general: need to obtain the exact enumerated domain

            if (m_config.IsNormalTracing)
            {
                var builder = new StringBuilder();
                Cell.CellsToBuilder(builder, m_cellGroup);
                Helpers.StringTraceLine(builder.ToString());
            }

            m_config.SetTimeForFinishedActivity(PerfType.CellCreation);
            // Check if the cellgroup is consistent and all known S constraints are
            // satisified by the known C constraints
            var validator = new CellGroupValidator(m_cellGroup, m_config);
            var errorLog = validator.Validate();

            if (errorLog.Count > 0)
            {
                errorLog.PrintTrace();
                return errorLog;
            }

            m_config.SetTimeForFinishedActivity(PerfType.KeyConstraint);

            // We generate update views first since they perform the main
            // validation checks
            if (m_config.GenerateUpdateViews)
            {
                errorLog = GenerateDirectionalViews(ViewTarget.UpdateView, identifiers, views);
                if (errorLog.Count > 0)
                {
                    return errorLog; // If we have discovered errors here, do not generate query views
                }
            }

            // Make sure that the foreign key constraints are not violated
            if (m_config.IsValidationEnabled)
            {
                CheckForeignKeyConstraints(errorLog);
            }
            m_config.SetTimeForFinishedActivity(PerfType.ForeignConstraint);

            if (errorLog.Count > 0)
            {
                errorLog.PrintTrace();
                return errorLog; // If we have discovered errors here, do not generate query views
            }

            // Query views - do not allow missing attributes
            // For the S-side, we add NOT ... for each scalar constant so
            // that if we have C, P in the mapping but the store has C, P, S,
            // we can handle it in the query views
            m_updateDomainMap.ExpandDomainsToIncludeAllPossibleValues();

            errorLog = GenerateDirectionalViews(ViewTarget.QueryView, identifiers, views);

            return errorLog;
        }
Esempio n. 13
0
        private ErrorLog GenerateQueryViewForExtentAndType(
            CqlIdentifiers identifiers, ViewSet views, EntitySetBase entity, EntityTypeBase type, ViewGenMode mode)
        {
            Debug.Assert(mode != ViewGenMode.GenerateAllViews);

            // Keep track of the mapping exceptions that we have generated
            var errorLog = new ErrorLog();

            if (m_config.IsViewTracing)
            {
                Helpers.StringTraceLine(String.Empty);
                Helpers.StringTraceLine(String.Empty);
                Helpers.FormatTraceLine(
                    "================= Generating {0} Query View for: {1} ===========================",
                    (mode == ViewGenMode.OfTypeViews) ? "OfType" : "OfTypeOnly",
                    entity.Name);
                Helpers.StringTraceLine(String.Empty);
                Helpers.StringTraceLine(String.Empty);
            }

            try
            {
                // (1) view generation (checks that extents are fully mapped)
                var context = CreateViewgenContext(entity, ViewTarget.QueryView, identifiers);
                var queryRewriter = GenerateViewsForExtentAndType(type, context, identifiers, views, mode);
            }
            catch (InternalMappingException exception)
            {
                // All exceptions have mapping errors in them
                Debug.Assert(exception.ErrorLog.Count > 0, "Incorrectly created mapping exception");
                errorLog.Merge(exception.ErrorLog);
            }

            return errorLog;
        }
Esempio n. 14
0
 internal void GetIdentifiers(CqlIdentifiers identifiers)
 {
     this.m_cQuery.GetIdentifiers(identifiers);
     this.m_sQuery.GetIdentifiers(identifiers);
 }
 /// <summary>
 ///     Creates a union block with SELECT (<paramref name="slotInfos" />), FROM (<paramref name="children" />), WHERE (true), AS (
 ///     <paramref
 ///         name="blockAliasNum" />
 ///     ).
 /// </summary>
 internal UnionCqlBlock(SlotInfo[] slotInfos, List<CqlBlock> children, CqlIdentifiers identifiers, int blockAliasNum)
     : base(slotInfos, children, BoolExpression.True, identifiers, blockAliasNum)
 {
 }
 /// <summary>
 ///     Creates a boolean expression for the variable name specified by <paramref name="index" />, e.g., 0 results in from0, 1 into from1.
 /// </summary>
 internal CellIdBoolean(CqlIdentifiers identifiers, int index)
 {
     Debug.Assert(index >= 0);
     m_index = index;
     m_slotName = identifiers.GetFromVariable(index);
 }
Esempio n. 17
0
 // <summary>
 // Creates a boolean expression for the variable name specified by <paramref name="index" />, e.g., 0 results in from0, 1 into from1.
 // </summary>
 internal CellIdBoolean(CqlIdentifiers identifiers, int index)
 {
     Debug.Assert(index >= 0);
     m_index    = index;
     m_slotName = identifiers.GetFromVariable(index);
 }
 /// <summary>
 ///     Creates a boolean of the form "<paramref name="block" />.<paramref name="originalCellNum" />".
 /// </summary>
 internal QualifiedCellIdBoolean(CqlBlock block, CqlIdentifiers identifiers, int originalCellNum)
     : base(identifiers, originalCellNum)
 {
     m_block = block;
 }
Esempio n. 19
0
        // requires: caseForOuterJoins corresponds the slot "slotNum"
        // effects: Adds a WhenThen corresponding to child to caseForOuterJoins.
        private void AddCaseForOuterJoins(CaseStatement caseForOuterJoins, CqlBlock child, int slotNum, CqlIdentifiers identifiers)
        {
            // Determine the cells that the slot comes from
            // and make an OR expression, e.g., WHEN _from0 or _from2 or ... THEN child[slotNum]

            var childSlot    = child.SlotValue(slotNum);
            var constantSlot = childSlot as ConstantProjectedSlot;

            if (constantSlot != null &&
                constantSlot.CellConstant.IsNull())
            {
                // NULL being generated by a child - don't need to project
                return;
            }

            var originBool = BoolExpression.False;

            for (var i = 0; i < NumBoolSlots; i++)
            {
                var boolSlotNum = BoolIndexToSlot(i);
                if (child.IsProjected(boolSlotNum))
                {
                    // OR it to the expression
                    var boolExpr = new QualifiedCellIdBoolean(child, identifiers, i);
                    originBool = BoolExpression.CreateOr(originBool, BoolExpression.CreateLiteral(boolExpr, RightDomainMap));
                }
            }
            // Qualify the slotNum with the child.CqlAlias for the THEN
            var slot = child.QualifySlotWithBlockAlias(slotNum);

            caseForOuterJoins.AddWhenThen(originBool, slot);
        }
Esempio n. 20
0
        // 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
                var unrequiredSlotInfo = new SlotInfo(false, false, null, GetMemberPath(slotNum));
                return(unrequiredSlotInfo);
            }

            // For a required slot, determine the child who is contributing to this value
            var           childDefiningSlot = -1;
            CaseStatement caseForOuterJoins = null;

            for (var childNum = 0; childNum < children.Count; childNum++)
            {
                var 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)
                        {
                            var 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;
                }
            }

            var           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));
                }
            }

            // 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.
            var 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
            var slotInfo = new SlotInfo(true, true, slot, memberPath, enforceNotNull);

            return(slotInfo);
        }
Esempio n. 21
0
 // effects: Determines all the identifiers used in this and adds them to identifiers
 internal void GetIdentifiers(CqlIdentifiers identifiers)
 {
     foreach (var projectedSlot in m_projectedSlots)
     {
         var slot = projectedSlot as MemberProjectedSlot;
         if (slot != null)
         {
             slot.MemberPath.GetIdentifiers(identifiers);
         }
     }
     m_extentMemberPath.GetIdentifiers(identifiers);
 }
Esempio n. 22
0
        private QueryRewriter GenerateViewsForExtentAndType(
            EdmType generatedType, ViewgenContext context, CqlIdentifiers identifiers, ViewSet views, ViewGenMode mode)
        {
            Debug.Assert(mode != ViewGenMode.GenerateAllViews, "By definition this method can not handle generating views for all extents");

            var queryRewriter = new QueryRewriter(generatedType, context, mode);
            queryRewriter.GenerateViewComponents();

            // Get the basic view
            var basicView = queryRewriter.BasicView;

            if (m_config.IsNormalTracing)
            {
                Helpers.StringTrace("Basic View: ");
                Helpers.StringTraceLine(basicView.ToString());
            }

            var simplifiedView = GenerateSimplifiedView(basicView, queryRewriter.UsedCells);

            if (m_config.IsNormalTracing)
            {
                Helpers.StringTraceLine(String.Empty);
                Helpers.StringTrace("Simplified View: ");
                Helpers.StringTraceLine(simplifiedView.ToString());
            }

            var cqlGen = new CqlGenerator(
                simplifiedView,
                queryRewriter.CaseStatements,
                identifiers,
                context.MemberMaps.ProjectedSlotMap,
                queryRewriter.UsedCells.Count,
                queryRewriter.TopLevelWhereClause,
                m_entityContainerMapping.StorageMappingItemCollection);

            string eSQLView;
            DbQueryCommandTree commandTree;
            if (m_config.GenerateEsql)
            {
                eSQLView = cqlGen.GenerateEsql();
                commandTree = null;
            }
            else
            {
                eSQLView = null;
                commandTree = cqlGen.GenerateCqt();
            }

            var generatedView = GeneratedView.CreateGeneratedView(
                context.Extent, generatedType, commandTree, eSQLView, m_entityContainerMapping.StorageMappingItemCollection, m_config);
            views.Add(context.Extent, generatedView);

            return queryRewriter;
        }
        // effects: Given a list of cells in the schema, generates the query and
        // update mapping views for OFTYPE(Extent, Type) combinations in this schema
        // container. Returns a list of generated query and update views.
        // If it is false and some columns in a table are unmapped, an
        // exception is raised
        private static ViewGenResults GenerateViewsFromCells(
            List<Cell> cells, ConfigViewGenerator config,
            CqlIdentifiers identifiers,
            EntityContainerMapping containerMapping)
        {
            DebugCheck.NotNull(cells);
            DebugCheck.NotNull(config);
            Debug.Assert(cells.Count > 0, "There must be at least one cell in the container mapping");

            // Go through each table and determine their foreign key constraints
            var container = containerMapping.StorageEntityContainer;
            Debug.Assert(container != null);

            var viewGenResults = new ViewGenResults();
            var tmpLog = EnsureAllCSpaceContainerSetsAreMapped(cells, containerMapping);
            if (tmpLog.Count > 0)
            {
                viewGenResults.AddErrors(tmpLog);
                Helpers.StringTraceLine(viewGenResults.ErrorsToString());
                return viewGenResults;
            }

            var foreignKeyConstraints = ForeignConstraint.GetForeignConstraints(container);

            var partitioner = new CellPartitioner(cells, foreignKeyConstraints);
            var cellGroups = partitioner.GroupRelatedCells();
            foreach (var cellGroup in cellGroups)
            {
                ViewGenerator viewGenerator = null;
                var groupErrorLog = new ErrorLog();
                try
                {
                    viewGenerator = new ViewGenerator(cellGroup, config, foreignKeyConstraints, containerMapping);
                }
                catch (InternalMappingException exception)
                {
                    // All exceptions have mapping errors in them
                    Debug.Assert(exception.ErrorLog.Count > 0, "Incorrectly created mapping exception");
                    groupErrorLog = exception.ErrorLog;
                }

                if (groupErrorLog.Count == 0)
                {
                    Debug.Assert(viewGenerator != null);
                    groupErrorLog = viewGenerator.GenerateAllBidirectionalViews(viewGenResults.Views, identifiers);
                }

                if (groupErrorLog.Count != 0)
                {
                    viewGenResults.AddErrors(groupErrorLog);
                }
            }
            // We used to print the errors here. Now we trace them as they are being thrown
            //if (viewGenResults.HasErrors && config.IsViewTracing) {
            //    Helpers.StringTraceLine(viewGenResults.ErrorsToString());
            //}
            return viewGenResults;
        }
Esempio n. 24
0
 // effects: Determines all the identifiers used in this and adds them to identifiers
 internal void GetIdentifiers(CqlIdentifiers identifiers)
 {
     m_cQuery.GetIdentifiers(identifiers);
     m_sQuery.GetIdentifiers(identifiers);
 }
Esempio n. 25
0
        internal ErrorLog GenerateQueryViewForSingleExtent(
            ViewSet views, CqlIdentifiers identifiers, EntitySetBase entity, EntityTypeBase type, ViewGenMode mode)
        {
            Debug.Assert(mode != ViewGenMode.GenerateAllViews);

            if (m_config.IsNormalTracing)
            {
                var builder = new StringBuilder();
                Cell.CellsToBuilder(builder, m_cellGroup);
                Helpers.StringTraceLine(builder.ToString());
            }

            // Check if the cellgroup is consistent and all known S constraints are
            // satisified by the known C constraints
            var validator = new CellGroupValidator(m_cellGroup, m_config);
            var errorLog = validator.Validate();
            if (errorLog.Count > 0)
            {
                errorLog.PrintTrace();
                return errorLog;
            }

            // Make sure that the foreign key constraints are not violated
            if (m_config.IsValidationEnabled)
            {
                CheckForeignKeyConstraints(errorLog);
            }

            if (errorLog.Count > 0)
            {
                errorLog.PrintTrace();
                return errorLog; // If we have discovered errors here, do not generate query views
            }

            // For the S-side, we add NOT ... for each scalar constant so
            // that if we have C, P in the mapping but the store has C, P, S,
            // we can handle it in the query views
            m_updateDomainMap.ExpandDomainsToIncludeAllPossibleValues();

            foreach (var cell in m_cellGroup)
            {
                cell.SQuery.WhereClause.FixDomainMap(m_updateDomainMap);
            }

            errorLog = GenerateQueryViewForExtentAndType(identifiers, views, entity, type, mode);

            return errorLog;
        }
Esempio n. 26
0
        internal override CqlBlock ToCqlBlock(
            bool[] requiredSlots, CqlIdentifiers identifiers, ref int blockAliasNum, ref List <WithRelationship> withRelationships)
        {
            // Get the projected slots and the boolean expressions
            var totalSlots = requiredSlots.Length;
            var cellQuery  = LeftCellWrapper.RightCellQuery;

            var 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 (var i = 0; i < cellQuery.NumProjectedSlots; i++)
            {
                var 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)
                {
                    var memberPath   = ProjectedSlotMap[i];
                    var defaultValue =
                        new ConstantProjectedSlot(Domain.GetDefaultValueForMemberPath(memberPath, GetLeaves(), ViewgenContext.Config));
                    cellQuery.FixMissingSlotAsDefaultConstant(i, defaultValue);
                    slot = defaultValue;
                }
                var slotInfo = new SlotInfo(
                    requiredSlots[i], slot != null,
                    slot, ProjectedSlotMap[i]);
                projectedSlots[i] = slotInfo;
            }

            // Add the boolean fields
            for (var boolNum = 0; boolNum < cellQuery.NumBoolVars; boolNum++)
            {
                var expr = cellQuery.GetBoolVar(boolNum);
                BooleanProjectedSlot boolSlot;
                if (expr != null)
                {
                    boolSlot = new BooleanProjectedSlot(expr, identifiers, boolNum);
                }
                else
                {
                    boolSlot = new BooleanProjectedSlot(BoolExpression.False, identifiers, boolNum);
                }
                var slotIndex = BoolIndexToSlot(boolNum);
                var 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) &&
                (m_cellWrapper.LeftExtent.BuiltInTypeKind == BuiltInTypeKind.EntitySet))
            {
                var associationSetMaps =
                    ViewgenContext.EntityContainerMapping.GetRelationshipSetMappingsFor(m_cellWrapper.LeftExtent, cellQuery.Extent);
                var foreignKeySlots = new List <SlotInfo>();
                foreach (var colocatedAssociationSetMap in associationSetMaps)
                {
                    WithRelationship withRelationship;
                    if (TryGetWithRelationship(
                            colocatedAssociationSetMap, m_cellWrapper.LeftExtent, cellQuery.SourceExtentMemberPath, ref foreignKeySlots,
                            out withRelationship))
                    {
                        withRelationships.Add(withRelationship);
                        totalProjectedSlots = projectedSlots.Concat(foreignKeySlots);
                    }
                }
            }
            var result = new ExtentCqlBlock(
                cellQuery.Extent, cellQuery.SelectDistinctFlag, totalProjectedSlots.ToArray(),
                cellQuery.WhereClause, identifiers, ++blockAliasNum);

            return(result);
        }
Esempio n. 27
0
        // requires: schema refers to C-side or S-side schema for the cells
        // inside this. if schema.IsQueryView is true, the left side of cells refers
        // to the C side (and vice-versa for the right side)
        // effects: Generates the relevant views for the schema side and
        // returns them. If allowMissingAttributes is true and attributes
        // are missing on the schema side, substitutes them with NULL
        // Modifies views to contain the generated views for different
        // extents specified by cells and the the schemaContext
        private ErrorLog GenerateDirectionalViews(ViewTarget viewTarget, CqlIdentifiers identifiers, ViewSet views)
        {
            var isQueryView = viewTarget == ViewTarget.QueryView;

            // Partition cells by extent.
            var extentCellMap = GroupCellsByExtent(m_cellGroup, viewTarget);

            // Keep track of the mapping exceptions that we have generated
            var errorLog = new ErrorLog();

            // Generate views for each extent
            foreach (var extent in extentCellMap.Keys)
            {
                if (m_config.IsViewTracing)
                {
                    Helpers.StringTraceLine(String.Empty);
                    Helpers.StringTraceLine(String.Empty);
                    Helpers.FormatTraceLine(
                        "================= Generating {0} View for: {1} ===========================",
                        isQueryView ? "Query" : "Update", extent.Name);
                    Helpers.StringTraceLine(String.Empty);
                    Helpers.StringTraceLine(String.Empty);
                }
                try
                {
                    // (1) view generation (checks that extents are fully mapped)
                    var queryRewriter = GenerateDirectionalViewsForExtent(viewTarget, extent, identifiers, views);

                    // (2) validation for update views
                    if (viewTarget == ViewTarget.UpdateView
                        &&
                        m_config.IsValidationEnabled)
                    {
                        if (m_config.IsViewTracing)
                        {
                            Helpers.StringTraceLine(String.Empty);
                            Helpers.StringTraceLine(String.Empty);
                            Helpers.FormatTraceLine(
                                "----------------- Validation for generated update view for: {0} -----------------",
                                extent.Name);
                            Helpers.StringTraceLine(String.Empty);
                            Helpers.StringTraceLine(String.Empty);
                        }

                        var validator = new RewritingValidator(queryRewriter.ViewgenContext, queryRewriter.BasicView);
                        validator.Validate();
                    }
                }
                catch (InternalMappingException exception)
                {
                    // All exceptions have mapping errors in them
                    Debug.Assert(
                        exception.ErrorLog.Count > 0,
                        "Incorrectly created mapping exception");
                    errorLog.Merge(exception.ErrorLog);
                }
            }
            return errorLog;
        }
Esempio n. 28
0
 internal CaseCqlBlock(
     SlotInfo[] slots, int caseSlot, CqlBlock child, BoolExpression whereClause, CqlIdentifiers identifiers, int blockAliasNum)
     : base(slots, new List<CqlBlock>(new[] { child }), whereClause, identifiers, blockAliasNum)
 {
     m_caseSlotInfo = slots[caseSlot];
 }
Esempio n. 29
0
        // effects: Returns a context corresponding to extent (if one does not exist, creates one)
        private ViewgenContext CreateViewgenContext(EntitySetBase extent, ViewTarget viewTarget, CqlIdentifiers identifiers)
        {
            QueryRewriter queryRewriter;
            if (!m_queryRewriterCache.TryGetValue(extent, out queryRewriter))
            {
                // collect the cells that belong to this extent (just a few of them since we segment the mapping first)
                var cellsForExtent = m_cellGroup.Where(c => c.GetLeftQuery(viewTarget).Extent == extent);

                return new ViewgenContext(
                    viewTarget, extent, cellsForExtent, identifiers, m_config, m_queryDomainMap, m_updateDomainMap, m_entityContainerMapping);
            }
            else
            {
                return queryRewriter.ViewgenContext;
            }
        }
Esempio n. 30
0
        // requires: node corresponds to a Union node
        // effects: Given a union node and the slots required by the parent,
        // generates a CqlBlock for the subtree rooted at node
        private CqlBlock UnionToCqlBlock(
            bool[] requiredSlots, CqlIdentifiers identifiers, ref int blockAliasNum, ref List <WithRelationship> withRelationships)
        {
            Debug.Assert(OpType == CellTreeOpType.Union);

            var children             = new List <CqlBlock>();
            var additionalChildSlots = new List <Tuple <CqlBlock, SlotInfo> >();

            var totalSlots = requiredSlots.Length;

            foreach (var child in Children)
            {
                // Unlike Join, we pass the requiredSlots from the parent as the requirement.
                var childProjectedSlots = child.GetProjectedSlots();
                AndWith(childProjectedSlots, requiredSlots);
                var childBlock = child.ToCqlBlock(childProjectedSlots, identifiers, ref blockAliasNum, ref withRelationships);
                for (var qualifiedSlotNumber = childProjectedSlots.Length;
                     qualifiedSlotNumber < childBlock.Slots.Count;
                     qualifiedSlotNumber++)
                {
                    additionalChildSlots.Add(Tuple.Create(childBlock, childBlock.Slots[qualifiedSlotNumber]));
                }

                // if required, but not projected, add NULL
                var paddedSlotInfo = new SlotInfo[childBlock.Slots.Count];
                for (var slotNum = 0; slotNum < totalSlots; slotNum++)
                {
                    if (requiredSlots[slotNum] &&
                        !childProjectedSlots[slotNum])
                    {
                        if (IsBoolSlot(slotNum))
                        {
                            paddedSlotInfo[slotNum] = new SlotInfo(
                                true /* is required */, true /* is projected */,
                                new BooleanProjectedSlot(BoolExpression.False, identifiers, SlotToBoolIndex(slotNum)), null /* member path*/);
                        }
                        else
                        {
                            // NULL as projected slot
                            var memberPath = childBlock.MemberPath(slotNum);
                            paddedSlotInfo[slotNum] = new SlotInfo(
                                true /* is required */, true /* is projected */,
                                new ConstantProjectedSlot(Constant.Null), memberPath);
                        }
                    }
                    else
                    {
                        paddedSlotInfo[slotNum] = childBlock.Slots[slotNum];
                    }
                }
                childBlock.Slots = new ReadOnlyCollection <SlotInfo>(paddedSlotInfo);
                children.Add(childBlock);
                Debug.Assert(
                    totalSlots == child.NumBoolSlots + child.NumProjectedSlots,
                    "Number of required slots is different from what each node in the tree has?");
            }

            // We need to add the slots added by each child uniformly for others (as nulls) since this is a union operation.
            if (additionalChildSlots.Count != 0)
            {
                foreach (var childBlock in children)
                {
                    var childSlots = new SlotInfo[totalSlots + additionalChildSlots.Count];
                    childBlock.Slots.CopyTo(childSlots, 0);
                    var index = totalSlots;
                    foreach (var additionalChildSlotInfo in additionalChildSlots)
                    {
                        var slotInfo = additionalChildSlotInfo.Item2;
                        if (additionalChildSlotInfo.Item1.Equals(childBlock))
                        {
                            childSlots[index] = new SlotInfo(
                                true /* is required */, true /* is projected */, slotInfo.SlotValue, slotInfo.OutputMember);
                        }
                        else
                        {
                            childSlots[index] = new SlotInfo(
                                true /* is required */, true /* is projected */,
                                new ConstantProjectedSlot(Constant.Null), slotInfo.OutputMember);
                        }
                        //move on to the next slot added by children.
                        index++;
                    }
                    childBlock.Slots = new ReadOnlyCollection <SlotInfo>(childSlots);
                }
            }

            // Create the slotInfos and then Union CqlBlock
            var slotInfos = new SlotInfo[totalSlots + additionalChildSlots.Count];

            // We pick the slot references from the first child, just as convention
            // In a union, values come from both sides
            var firstChild = children[0];

            for (var slotNum = 0; slotNum < totalSlots; slotNum++)
            {
                var slotInfo = firstChild.Slots[slotNum];
                // A required slot is somehow projected by a child in Union, so set isProjected to be the same as isRequired.
                var isRequired = requiredSlots[slotNum];
                slotInfos[slotNum] = new SlotInfo(isRequired, isRequired, slotInfo.SlotValue, slotInfo.OutputMember);
            }

            for (var slotNum = totalSlots; slotNum < totalSlots + additionalChildSlots.Count; slotNum++)
            {
                var aslot = firstChild.Slots[slotNum];
                slotInfos[slotNum] = new SlotInfo(true, true, aslot.SlotValue, aslot.OutputMember);
            }

            CqlBlock block = new UnionCqlBlock(slotInfos, children, identifiers, ++blockAliasNum);

            return(block);
        }
 // effects: Creates a cell creator object for an entity container's
 // mappings (specified in "maps")
 internal CellCreator(StorageEntityContainerMapping containerMapping)
 {
     m_containerMapping = containerMapping;
     m_identifiers = new CqlIdentifiers();
 }
        private CqlBlock UnionToCqlBlock(
            bool[] requiredSlots,
            CqlIdentifiers identifiers,
            ref int blockAliasNum,
            ref List <WithRelationship> withRelationships)
        {
            List <CqlBlock> children = new List <CqlBlock>();
            List <Tuple <CqlBlock, SlotInfo> > tupleList = new List <Tuple <CqlBlock, SlotInfo> >();
            int length1 = requiredSlots.Length;

            foreach (CellTreeNode child in this.Children)
            {
                bool[] projectedSlots = child.GetProjectedSlots();
                OpCellTreeNode.AndWith(projectedSlots, requiredSlots);
                CqlBlock cqlBlock = child.ToCqlBlock(projectedSlots, identifiers, ref blockAliasNum, ref withRelationships);
                for (int length2 = projectedSlots.Length; length2 < cqlBlock.Slots.Count; ++length2)
                {
                    tupleList.Add(Tuple.Create <CqlBlock, SlotInfo>(cqlBlock, cqlBlock.Slots[length2]));
                }
                SlotInfo[] slotInfoArray = new SlotInfo[cqlBlock.Slots.Count];
                for (int slotNum = 0; slotNum < length1; ++slotNum)
                {
                    if (requiredSlots[slotNum] && !projectedSlots[slotNum])
                    {
                        if (this.IsBoolSlot(slotNum))
                        {
                            slotInfoArray[slotNum] = new SlotInfo(true, true, (ProjectedSlot) new BooleanProjectedSlot(BoolExpression.False, identifiers, this.SlotToBoolIndex(slotNum)), (MemberPath)null);
                        }
                        else
                        {
                            MemberPath outputMember = cqlBlock.MemberPath(slotNum);
                            slotInfoArray[slotNum] = new SlotInfo(true, true, (ProjectedSlot) new ConstantProjectedSlot(Constant.Null), outputMember);
                        }
                    }
                    else
                    {
                        slotInfoArray[slotNum] = cqlBlock.Slots[slotNum];
                    }
                }
                cqlBlock.Slots = new ReadOnlyCollection <SlotInfo>((IList <SlotInfo>)slotInfoArray);
                children.Add(cqlBlock);
            }
            if (tupleList.Count != 0)
            {
                foreach (CqlBlock cqlBlock in children)
                {
                    SlotInfo[] array = new SlotInfo[length1 + tupleList.Count];
                    cqlBlock.Slots.CopyTo(array, 0);
                    int index = length1;
                    foreach (Tuple <CqlBlock, SlotInfo> tuple in tupleList)
                    {
                        SlotInfo slotInfo = tuple.Item2;
                        array[index] = !tuple.Item1.Equals((object)cqlBlock) ? new SlotInfo(true, true, (ProjectedSlot) new ConstantProjectedSlot(Constant.Null), slotInfo.OutputMember) : new SlotInfo(true, true, slotInfo.SlotValue, slotInfo.OutputMember);
                        ++index;
                    }
                    cqlBlock.Slots = new ReadOnlyCollection <SlotInfo>((IList <SlotInfo>)array);
                }
            }
            SlotInfo[] slotInfos = new SlotInfo[length1 + tupleList.Count];
            CqlBlock   cqlBlock1 = children[0];

            for (int index = 0; index < length1; ++index)
            {
                SlotInfo slot         = cqlBlock1.Slots[index];
                bool     requiredSlot = requiredSlots[index];
                slotInfos[index] = new SlotInfo(requiredSlot, requiredSlot, slot.SlotValue, slot.OutputMember);
            }
            for (int index = length1; index < length1 + tupleList.Count; ++index)
            {
                SlotInfo slot = cqlBlock1.Slots[index];
                slotInfos[index] = new SlotInfo(true, true, slot.SlotValue, slot.OutputMember);
            }
            return((CqlBlock) new UnionCqlBlock(slotInfos, children, identifiers, ++blockAliasNum));
        }