示例#1
0
        public override bool UpdateDataQuerySelects(CallNode callNode, TexlBinding binding, DataSourceToQueryOptionsMap dataSourceToQueryOptionsMap)
        {
            Contracts.AssertValue(callNode);
            Contracts.AssertValue(binding);

            // Ignore delegation warning
            if (!CheckArgsCount(callNode, binding, DocumentErrorSeverity.Moderate))
            {
                return(false);
            }

            TexlNode[] args = callNode.Args.Children.VerifyValue();

            DType dsType = binding.GetType(args[0]);

            if (dsType.AssociatedDataSources == null)
            {
                return(false);
            }

            DType      columnType = binding.GetType(args[1]);
            StrLitNode columnNode = args[1].AsStrLit();

            if (columnType.Kind != DKind.String || columnNode == null)
            {
                return(false);
            }
            string columnName = columnNode.Value;

            Contracts.Assert(dsType.Contains(new DName(columnName)));

            return(dsType.AssociateDataSourcesToSelect(dataSourceToQueryOptionsMap, columnName, columnType, true));
        }
示例#2
0
        public override bool UpdateDataQuerySelects(CallNode callNode, TexlBinding binding, DataSourceToQueryOptionsMap dataSourceToQueryOptionsMap)
        {
            Contracts.AssertValue(callNode);
            Contracts.AssertValue(binding);

            if (!CheckArgsCount(callNode, binding))
            {
                return(false);
            }

            TexlNode[] args = callNode.Args.Children.VerifyValue();

            DType dsType = binding.GetType(args[0]);

            if (dsType.AssociatedDataSources == null)
            {
                return(false);
            }

            var resultType = binding.GetType(callNode).VerifyValue();

            bool retval = false;

            foreach (var typedName in resultType.GetNames(DPath.Root))
            {
                DType  columnType = typedName.Type;
                string columnName = typedName.Name.Value;

                Contracts.Assert(dsType.Contains(new DName(columnName)));

                retval |= dsType.AssociateDataSourcesToSelect(dataSourceToQueryOptionsMap, columnName, columnType, true);
            }
            return(retval);
        }
        public override bool IsServerDelegatable(CallNode callNode, TexlBinding binding)
        {
            Contracts.AssertValue(callNode);
            Contracts.AssertValue(binding);

            if (FunctionDelegationCapability.Capabilities == DelegationCapability.None)
            {
                return(false);
            }

            if (!CheckArgsCount(callNode, binding))
            {
                return(false);
            }

            IExternalDataSource dataSource;

            if (!TryGetValidDataSourceForDelegation(callNode, binding, FunctionDelegationCapability, out dataSource))
            {
                if (dataSource != null && dataSource.IsDelegatable)
                {
                    binding.ErrorContainer.EnsureError(DocumentErrorSeverity.Warning, callNode, TexlStrings.OpNotSupportedByServiceSuggestionMessage_OpNotSupportedByService, Name);
                }

                return(false);
            }

            var args = callNode.Args.Children.VerifyValue();

            if (binding.GetType(args[0]).HasExpandInfo ||
                (!binding.IsFullRecordRowScopeAccess(args[1]) && args[1].Kind != NodeKind.FirstName) ||
                !binding.IsRowScope(args[1]) ||
                binding.GetType(args[1]) != DType.Number ||
                ExpressionContainsView(callNode, binding))
            {
                SuggestDelegationHint(callNode, binding);

                if (binding.GetType(args[1]) != DType.Number)
                {
                    DelegationTrackerCore.SetDelegationTrackerStatus(DelegationStatus.NotANumberArgType, callNode, binding, this, DelegationTelemetryInfo.CreateEmptyDelegationTelemetryInfo());
                }
                else
                {
                    DelegationTrackerCore.SetDelegationTrackerStatus(DelegationStatus.InvalidArgType, callNode, binding, this, DelegationTelemetryInfo.CreateEmptyDelegationTelemetryInfo());
                }

                return(false);
            }

            if (binding.IsFullRecordRowScopeAccess(args[1]))
            {
                return(GetDottedNameNodeDelegationStrategy().IsValidDottedNameNode(args[1].AsDottedName(), binding, null, null));
            }

            var firstNameStrategy = GetFirstNameNodeDelegationStrategy().VerifyValue();

            return(firstNameStrategy.IsValidFirstNameNode(args[1].AsFirstName(), binding, null));
        }
示例#4
0
        private bool DoCoercionCheck(BinaryOpNode binaryOpNode, OperationCapabilityMetadata metadata, TexlBinding binding)
        {
            Contracts.AssertValue(binaryOpNode);
            Contracts.AssertValue(metadata);
            Contracts.AssertValue(binding);

            DType leftType  = binding.GetType(binaryOpNode.Left);
            DType rightType = binding.GetType(binaryOpNode.Right);

            switch (leftType.Kind)
            {
            case DKind.Date:
                if (rightType.Kind == DKind.DateTime)
                {
                    // If rhs is a column of type DateTime and lhs is row scoped then we will need to apply the coercion on rhs. So check if coercion function date is supported or not.
                    if (IsColumnNode(binaryOpNode.Right, binding) && binding.IsRowScope(binaryOpNode.Left))
                    {
                        return(IsDelegatableColumnNode(binaryOpNode.Right.AsFirstName(), binding, null, DelegationCapability.Date));
                    }

                    // If lhs is rowscoped but not a field reference and rhs is rowscoped then we need to check if it's supported at table level.
                    if (binding.IsRowScope(binaryOpNode.Left) && binding.IsRowScope(binaryOpNode.Right))
                    {
                        return(metadata.IsDelegationSupportedByTable(DelegationCapability.Date));
                    }

                    return(true);
                }

                break;

            case DKind.DateTime:
                if (rightType.Kind == DKind.Date)
                {
                    // If lhs is a column of type DateTime and RHS is also row scoped then check if coercion function date is supported or not.
                    if (IsColumnNode(binaryOpNode.Left, binding) && binding.IsRowScope(binaryOpNode.Right))
                    {
                        return(IsDelegatableColumnNode(binaryOpNode.Left.AsFirstName(), binding, null, DelegationCapability.Date));
                    }

                    // If lhs is rowscoped but not a field reference and rhs is rowscoped then we need to check if it's supported at table level.
                    if (binding.IsRowScope(binaryOpNode.Left) && binding.IsRowScope(binaryOpNode.Right))
                    {
                        return(metadata.IsDelegationSupportedByTable(DelegationCapability.Date));
                    }

                    return(true);
                }

                break;

            default:
                break;
            }

            return(true);
        }
示例#5
0
        private bool TryGetEntityInfo(CallNode callNode, TexlBinding binding, out IExpandInfo entityInfo)
        {
            Contracts.AssertValueOrNull(callNode);
            Contracts.AssertValue(binding);

            entityInfo = null;
            if (callNode == null || !binding.GetType(callNode).IsTable)
            {
                return(false);
            }

            var callInfo = binding.GetInfo(callNode);

            if (callInfo == null)
            {
                return(false);
            }

            var function = callInfo.Function;

            if (function == null)
            {
                return(false);
            }

            return(function.TryGetEntityInfo(callNode, binding, out entityInfo));
        }
        private bool TryGetDsNode(FirstNameNode firstName, TexlBinding binding, out FirstNameNode dsNode)
        {
            Contracts.AssertValueOrNull(firstName);
            Contracts.AssertValue(binding);

            dsNode = null;
            if (firstName == null || !binding.GetType(firstName).IsTable)
            {
                return(false);
            }

            var firstNameInfo = binding.GetInfo(firstName);

            if (firstNameInfo == null || firstNameInfo.Kind != BindKind.Data)
            {
                return(false);
            }

            if (binding.EntityScope == null || !binding.EntityScope.TryGetEntity(firstNameInfo.Name, out IExternalDataSource _))
            {
                return(false);
            }

            dsNode = firstName;
            return(true);
        }
        private bool TryGetDsNodes(CallNode callNode, TexlBinding binding, out IList <FirstNameNode> dsInfos)
        {
            Contracts.AssertValueOrNull(callNode);
            Contracts.AssertValue(binding);

            dsInfos = new List <FirstNameNode>();
            if (callNode == null || !(binding.GetType(callNode).IsAggregate))
            {
                return(false);
            }

            var callInfo = binding.GetInfo(callNode);

            if (callInfo == null)
            {
                return(false);
            }

            var function = callInfo.Function;

            if (function == null)
            {
                return(false);
            }

            return(function.TryGetDataSourceNodes(callNode, binding, out dsInfos));
        }
        private bool TryGetDsInfo(CallNode callNode, TexlBinding binding, out IExternalDataSource dsInfo)
        {
            Contracts.AssertValueOrNull(callNode);
            Contracts.AssertValue(binding);

            dsInfo = null;
            if (callNode == null || !binding.IsDelegatable(callNode) || !binding.GetType(callNode).IsTable)
            {
                return(false);
            }

            var callInfo = binding.GetInfo(callNode);

            if (callInfo == null)
            {
                return(false);
            }

            var function = callInfo.Function;

            if (function == null)
            {
                return(false);
            }

            bool success = function.TryGetDataSource(callNode, binding, out var external);

            dsInfo = (IExternalDataSource)external;
            return(success);
        }
示例#9
0
        protected bool IsValidNode(TexlNode node, TexlBinding binding)
        {
            Contracts.AssertValue(node);
            Contracts.AssertValue(binding);

            bool isAsync = binding.IsAsync(node);
            bool isPure  = binding.IsPure(node);


            if (node is DottedNameNode &&
                ((binding.GetType(node.AsDottedName().Left).Kind == DKind.OptionSet && binding.GetType(node).Kind == DKind.OptionSetValue) ||
                 (binding.GetType(node.AsDottedName().Left).Kind == DKind.View && binding.GetType(node).Kind == DKind.ViewValue)))
            {
                // OptionSet and View Access are delegable despite being async
                return(true);
            }

            if (node is CallNode && (binding.IsBlockScopedConstant(node) ||
                                     (binding.GetInfo(node as CallNode).Function is AsTypeFunction)))
            {
                // AsType is delegable despite being async
                return(true);
            }

            // Async predicates and impure nodes are not supported.
            // Let CallNodes for User() be marked as being Valid to allow
            // expressions with User() calls to be delegated
            if (!(IsUserCallNodeDelegable(node, binding)) && (isAsync || !isPure))
            {
                var telemetryMessage = string.Format("Kind:{0}, isAsync:{1}, isPure:{2}", node.Kind, isAsync, isPure);
                SuggestDelegationHintAndAddTelemetryMessage(node, binding, telemetryMessage);

                if (isAsync)
                {
                    TrackingProvider.Instance.SetDelegationTrackerStatus(DelegationStatus.AsyncPredicate, node, binding, _function);
                }

                if (!isPure)
                {
                    TrackingProvider.Instance.SetDelegationTrackerStatus(DelegationStatus.ImpureNode, node, binding, _function, DelegationTelemetryInfo.CreateImpureNodeTelemetryInfo(node, binding));
                }

                return(false);
            }

            return(true);
        }
示例#10
0
        public override void PostVisit(DottedNameNode node)
        {
            var argType = _txb.GetType(node);

            if (argType.Kind == DKind.ViewValue)
            {
                ContainsView = true;
            }
        }
示例#11
0
        public override bool IsServerDelegatable(CallNode callNode, TexlBinding binding)
        {
            Contracts.AssertValue(callNode);
            Contracts.AssertValue(binding);

            if (!CheckArgsCount(callNode, binding))
            {
                return(false);
            }

            IExternalDataSource dataSource = null;

            // We ensure Document is available because some tests run with a null Document.
            if ((binding.Document != null && !binding.Document.Properties.EnabledFeatures.IsEnhancedDelegationEnabled) || !TryGetValidDataSourceForDelegation(callNode, binding, FunctionDelegationCapability, out dataSource))
            {
                if (dataSource != null && dataSource.IsDelegatable)
                {
                    binding.ErrorContainer.EnsureError(DocumentErrorSeverity.Warning, callNode, TexlStrings.OpNotSupportedByServiceSuggestionMessage_OpNotSupportedByService, Name);
                }

                return(false);
            }

            TexlNode[] args = callNode.Args.Children.VerifyValue();

            if (args.Length == 0)
            {
                return(false);
            }

            // Don't delegate 1-N/N-N counts
            // TASK 9966488: Enable CountRows/CountIf delegation for table relationships
            if (binding.GetType(args[0]).HasExpandInfo)
            {
                SuggestDelegationHint(callNode, binding);
                return(false);
            }

            FilterOpMetadata metadata = dataSource.DelegationMetadata.FilterDelegationMetadata;

            // Validate for each predicate node.
            for (int i = 1; i < args.Length; i++)
            {
                if (!IsValidDelegatableFilterPredicateNode(args[i], binding, metadata))
                {
                    SuggestDelegationHint(callNode, binding);
                    return(false);
                }
            }

            return(true);
        }
示例#12
0
        private bool TryGetEntityInfo(FirstNameNode firstName, TexlBinding binding, out IExpandInfo entityInfo)
        {
            Contracts.AssertValueOrNull(firstName);
            Contracts.AssertValue(binding);

            entityInfo = null;
            if (firstName == null || !binding.GetType(firstName).IsTable)
            {
                return(false);
            }

            return(binding.TryGetEntityInfo(firstName, out entityInfo));
        }
示例#13
0
        public override bool UpdateDataQuerySelects(CallNode callNode, TexlBinding binding, DataSourceToQueryOptionsMap dataSourceToQueryOptionsMap)
        {
            Contracts.AssertValue(callNode);
            Contracts.AssertValue(binding);

            if (!CheckArgsCount(callNode, binding, DocumentErrorSeverity.Moderate))
            {
                return(false);
            }

            TexlNode[] args = callNode.Args.Children.VerifyValue();

            DType dsType = binding.GetType(args[0]);

            if (dsType.AssociatedDataSources == null)
            {
                return(false);
            }

            bool retval = false;

            for (int i = 1; i < args.Length; i += 2)
            {
                DType      columnType = binding.GetType(args[i]);
                StrLitNode columnNode = args[i].AsStrLit();
                if (columnType.Kind != DKind.String || columnNode == null)
                {
                    continue;
                }
                string columnName = columnNode.Value;

                Contracts.Assert(dsType.Contains(new DName(columnName)));

                retval |= dsType.AssociateDataSourcesToSelect(dataSourceToQueryOptionsMap, columnName, columnType, true);
            }
            return(retval);
        }
 public override void PostVisit(CallNode node)
 {
     // Check if there is a filter node using view.
     if (node?.Head?.Name.Value == FilterFunctionName)
     {
         foreach (var arg in node.Args.Children)
         {
             var argType = _txb.GetType(arg);
             if (argType.Kind == DKind.ViewValue)
             {
                 ContainsViewFilter = true;
             }
         }
     }
 }
示例#15
0
        public bool IsRHSDelegableTable(TexlBinding binding, BinaryOpNode binaryOpNode, OperationCapabilityMetadata metadata)
        {
            Contracts.AssertValue(binding);
            Contracts.AssertValue(binaryOpNode);
            Contracts.AssertValue(metadata);

            var rightNodeType = binding.GetType(binaryOpNode.Right);

            var hasEnhancedDelegation = binding.Document.Properties.EnabledFeatures.IsEnhancedDelegationEnabled;
            var isColumn = rightNodeType?.IsColumn == true;
            var isDelegationSupportedByTable = metadata.IsDelegationSupportedByTable(DelegationCapability.CdsIn);
            var HasLeftFirstNameNodeOrIsFullRecordRowScopeAccess = binaryOpNode.Left?.AsFirstName() != null || binding.IsFullRecordRowScopeAccess(binaryOpNode.Left);

            return(hasEnhancedDelegation && isColumn && isDelegationSupportedByTable && HasLeftFirstNameNodeOrIsFullRecordRowScopeAccess);
        }
示例#16
0
        private bool VerifyFirstNameNodeIsValidSortOrderEnum(FirstNameNode node, TexlBinding binding)
        {
            Contracts.AssertValue(node);
            Contracts.AssertValue(binding);

            var firstNameInfo = binding.GetInfo(node);

            if (firstNameInfo == null || firstNameInfo.Kind != BindKind.Enum)
            {
                return(false);
            }


            if (!binding.NameResolver.TryLookupEnum(new DName(LanguageConstants.SortOrderEnumStringInvariant), out var lookupInfo))
            {
                return(false);
            }

            DType type = binding.GetType(node);

            return(type == lookupInfo.Type);
        }
示例#17
0
        // See if CountDistinct delegation is available. If true, we can make use of it on primary key as a workaround for CountRows delegation
        internal bool TryGetValidDataSourceForDelegation(CallNode callNode, TexlBinding binding, out IExternalDataSource dataSource, out DelegationCapability preferredFunctionDelegationCapability)
        {
            Contracts.AssertValue(callNode);
            Contracts.AssertValue(binding);

            preferredFunctionDelegationCapability = FunctionDelegationCapability;
            // We ensure Document is available because some tests run with a null Document.
            if ((binding.Document != null &&
                 binding.Document.Properties.EnabledFeatures.IsEnhancedDelegationEnabled) &&
                TryGetValidDataSourceForDelegation(callNode, binding, FunctionDelegationCapability, out dataSource) &&
                !ExpressionContainsView(callNode, binding))
            {
                // Check that target table is not an expanded entity (1-N/N-N relationships)
                // TASK 9966488: Enable CountRows/CountIf delegation for table relationships
                TexlNode[] args = callNode.Args.Children.VerifyValue();
                if (args.Length > 0)
                {
                    if (binding.GetType(args[0]).HasExpandInfo)
                    {
                        SuggestDelegationHint(callNode, binding);
                        return(false);
                    }
                    else
                    {
                        return(true);
                    }
                }
            }

            TryGetValidDataSourceForDelegation(callNode, binding, DelegationCapability.CountDistinct, out dataSource);
            if (dataSource != null && dataSource.IsDelegatable)
            {
                binding.ErrorContainer.EnsureError(DocumentErrorSeverity.Warning, callNode, TexlStrings.OpNotSupportedByServiceSuggestionMessage_OpNotSupportedByService, Name);
            }

            return(false);
        }
示例#18
0
        // Verifies if given kind of node is supported by function delegation.
        private bool IsSupportedNode(TexlNode node, OperationCapabilityMetadata metadata, TexlBinding binding, IOpDelegationStrategy opDelStrategy, bool isRHSNode)
        {
            Contracts.AssertValue(node);
            Contracts.AssertValue(metadata);
            Contracts.AssertValue(binding);
            Contracts.AssertValue(opDelStrategy);

            if (!binding.IsRowScope(node))
            {
                // Check whether this is -
                //  1) in operator delegation and
                //  2) it is verifying if RHS node is supported and
                //  3) it is not an async node and
                //  4) it is a single column table and
                //  5) metadata belongs to cds datasource that supports delegation of CdsIn
                // If this check fails, verify if it is simply a valid node..
                // Eg of valid delegation functions -
                // Filter(Accounts, 'Account Name' in ["Foo", Bar"]) - Direct table use
                // Set(Names, ["Foo", Bar"]); Filter(Accounts, 'Account Name' in Names) - Using variable of type table
                // ClearCollect(Names, Accounts); Filter(Accounts, 'Account Name' in Names.'Account Name') - using column from collection.
                // This won't be delegated - Filter(Accounts, 'Account Name' in Accounts.'Account Name') as Accounts.'Account Name' is async.
                if ((binding.Document.Properties.EnabledFeatures.IsEnhancedDelegationEnabled &&
                     isRHSNode && (opDelStrategy as BinaryOpDelegationStrategy)?.Op == BinaryOp.In && !binding.IsAsync(node) && binding.GetType(node).IsTable&& binding.GetType(node).IsColumn&&
                     metadata.IsDelegationSupportedByTable(DelegationCapability.CdsIn)) ||
                    IsValidNode(node, binding))
                {
                    return(true);
                }
            }

            switch (node.Kind)
            {
            case NodeKind.DottedName:
            {
                if (!opDelStrategy.IsOpSupportedByTable(metadata, node, binding))
                {
                    return(false);
                }

                var dottedNodeValStrategy = _function.GetDottedNameNodeDelegationStrategy();
                return(dottedNodeValStrategy.IsValidDottedNameNode(node.AsDottedName(), binding, metadata, opDelStrategy));
            }

            case NodeKind.Call:
            {
                if (!opDelStrategy.IsOpSupportedByTable(metadata, node, binding))
                {
                    return(false);
                }

                var cNodeValStrategy = _function.GetCallNodeDelegationStrategy();
                return(cNodeValStrategy.IsValidCallNode(node.AsCall(), binding, metadata));
            }

            case NodeKind.FirstName:
            {
                var firstNameNodeValStrategy = _function.GetFirstNameNodeDelegationStrategy();
                return(firstNameNodeValStrategy.IsValidFirstNameNode(node.AsFirstName(), binding, opDelStrategy));
            }

            case NodeKind.UnaryOp:
            {
                if (!opDelStrategy.IsOpSupportedByTable(metadata, node, binding))
                {
                    return(false);
                }

                var unaryopNode = node.AsUnaryOpLit();
                IOpDelegationStrategy unaryOpNodeDelegationStrategy = _function.GetOpDelegationStrategy(unaryopNode.Op);
                return(unaryOpNodeDelegationStrategy.IsSupportedOpNode(unaryopNode, metadata, binding));
            }

            case NodeKind.BinaryOp:
            {
                if (!opDelStrategy.IsOpSupportedByTable(metadata, node, binding))
                {
                    return(false);
                }

                var binaryOpNode = node.AsBinaryOp().VerifyValue();
                opDelStrategy = _function.GetOpDelegationStrategy(binaryOpNode.Op, binaryOpNode);

                var binaryOpDelStrategy = (opDelStrategy as BinaryOpDelegationStrategy).VerifyValue();
                Contracts.Assert(binaryOpNode.Op == binaryOpDelStrategy.Op);

                if (!opDelStrategy.IsSupportedOpNode(node, metadata, binding))
                {
                    SuggestDelegationHint(binaryOpNode, binding);
                    return(false);
                }

                break;
            }

            default:
            {
                var kind = node.Kind;
                if (kind != NodeKind.BoolLit && kind != NodeKind.StrLit && kind != NodeKind.NumLit)
                {
                    var telemetryMessage = string.Format("NodeKind {0} unsupported.", kind);
                    SuggestDelegationHintAndAddTelemetryMessage(node, binding, telemetryMessage);
                    return(false);
                }

                break;
            }
            }

            return(true);
        }
示例#19
0
        public virtual bool IsSupportedOpNode(TexlNode node, OperationCapabilityMetadata metadata, TexlBinding binding)
        {
            Contracts.AssertValue(node);
            Contracts.AssertValue(metadata);
            Contracts.AssertValue(binding);

            BinaryOpNode binaryOpNode = node.AsBinaryOp();

            if (binaryOpNode == null)
            {
                return(false);
            }

            IOpDelegationStrategy opDelStrategy = _function.GetOpDelegationStrategy(binaryOpNode.Op, binaryOpNode);
            var binaryOpDelStrategy             = (opDelStrategy as BinaryOpDelegationStrategy).VerifyValue();

            Contracts.Assert(binaryOpNode.Op == binaryOpDelStrategy.Op);

            // Check if binaryOp is supported by datasource in the context of filter operation.
            // If this is not allowed then there is no point in checking lhs and rhs
            // It's only safe to do so if lhs and rhs is first/dotted name node as columns (FirstName/DottedName node) can have additional capabilities defined.
            if (!(binaryOpNode.Left is FirstNameNode || binaryOpNode.Left is DottedNameNode) &&
                !(binaryOpNode.Right is FirstNameNode || binaryOpNode.Right is DottedNameNode) &&
                !opDelStrategy.IsOpSupportedByTable(metadata, node, binding))
            {
                var telemetryMessage = string.Format("{0} operator not supported at table level", binaryOpNode.Op.ToString());
                SuggestDelegationHintAndAddTelemetryMessage(node, binding, telemetryMessage);
                TrackingProvider.Instance.SetDelegationTrackerStatus(DelegationStatus.BinaryOpNoSupported, node, binding, _function, DelegationTelemetryInfo.CreateBinaryOpNoSupportedInfoTelemetryInfo(binaryOpNode.Op));
                return(false);
            }

            if (!ODataFunctionMappings.BinaryOpToOperatorMap.Value.ContainsKey(binaryOpNode.Op))
            {
                SuggestDelegationHint(node, binding);
                return(false);
            }

            if (!IsSupportedNode(binaryOpNode.Left, metadata, binding, opDelStrategy, false))
            {
                SuggestDelegationHint(node, binding);
                return(false);
            }

            if (!IsSupportedNode(binaryOpNode.Right, metadata, binding, opDelStrategy, true))
            {
                SuggestDelegationHint(node, binding);
                return(false);
            }

            DType leftType  = binding.GetType(binaryOpNode.Left);
            DType rightType = binding.GetType(binaryOpNode.Right);

            if ((leftType.IsPolymorphic && rightType.IsRecord) || (leftType.IsRecord && rightType.IsPolymorphic))
            {
                return(true);
            }

            if (!DoCoercionCheck(binaryOpNode, metadata, binding))
            {
                SuggestDelegationHint(node, binding);
                return(false);
            }

            return(true);
        }
示例#20
0
            public override void PostVisit(DottedNameNode node)
            {
                Contracts.AssertValue(node);

                DType                  lhsType = _txb.GetType(node.Left);
                DType                  typeRhs = DType.Invalid;
                DName                  nameRhs = node.Right.Name;
                FirstNameInfo          firstNameInfo;
                FirstNameNode          firstNameNode;
                IExternalTableMetadata tableMetadata;
                DType                  nodeType = DType.Unknown;

                if (node.Left.Kind != NodeKind.FirstName &&
                    node.Left.Kind != NodeKind.DottedName)
                {
                    SetDottedNameError(node, TexlStrings.ErrInvalidName);
                    return;
                }

                nameRhs = GetLogicalNodeNameAndUpdateDisplayNames(lhsType, node.Right);

                if (!lhsType.TryGetType(nameRhs, out typeRhs))
                {
                    SetDottedNameError(node, TexlStrings.ErrInvalidName);
                    return;
                }

                // There are two cases:
                // 1. RHS could be an option set.
                // 2. RHS could be a data entity.
                // 3. RHS could be a column name and LHS would be a datasource.
                if (typeRhs.IsOptionSet)
                {
                    nodeType = typeRhs;
                }
                else if (typeRhs.IsExpandEntity)
                {
                    var entityInfo = typeRhs.ExpandInfo;
                    Contracts.AssertValue(entityInfo);

                    string entityPath = string.Empty;
                    if (lhsType.HasExpandInfo)
                    {
                        entityPath = lhsType.ExpandInfo.ExpandPath.ToString();
                    }

                    DType expandedEntityType = GetExpandedEntityType(typeRhs, entityPath);

                    var parentDataSource = entityInfo.ParentDataSource;
                    var metadata         = new DataTableMetadata(parentDataSource.Name, parentDataSource.Name);
                    nodeType = DType.CreateMetadataType(new DataColumnMetadata(typeRhs.ExpandInfo.Name, expandedEntityType, metadata));
                }
                else if ((firstNameNode = node.Left.AsFirstName()) != null && (firstNameInfo = _txb.GetInfo(firstNameNode)) != null)
                {
                    var tabularDataSourceInfo = firstNameInfo.Data as IExternalTabularDataSource;
                    tableMetadata = tabularDataSourceInfo?.TableMetadata;
                    if (tableMetadata == null || !tableMetadata.TryGetColumn(nameRhs.Value, out var columnMetadata) || !IsColumnMultiChoice(columnMetadata))
                    {
                        SetDottedNameError(node, TexlStrings.ErrInvalidName);
                        return;
                    }

                    var metadata = new DataTableMetadata(tabularDataSourceInfo.Name, tableMetadata.DisplayName);
                    nodeType = DType.CreateMetadataType(new DataColumnMetadata(columnMetadata, metadata));
                }
                else
                {
                    SetDottedNameError(node, TexlStrings.ErrInvalidName);
                    return;
                }

                Contracts.AssertValid(nodeType);

                _txb.SetType(node, nodeType);
                _txb.SetInfo(node, new DottedNameInfo(node));
            }
示例#21
0
        public static bool TryGetExpectedTypeForBinaryOp(TexlBinding binding, TexlNode curNode, int cursorPos, out DType expectedType)
        {
            // If we are in a binary operation context, the expected type is relative to the binary operation.
            if (curNode != null && curNode.Parent != null && curNode.Parent.Kind == NodeKind.BinaryOp)
            {
                BinaryOpNode binaryOpNode = curNode.Parent.CastBinaryOp();
                DType        coercedType;
                TexlNode     expectedNode = null;
                if (cursorPos < binaryOpNode.Token.Span.Min)
                {
                    // Cursor is before the binary operator. Expected type is equal to the type of right side.
                    expectedNode = binaryOpNode.Right;
                }
                else if (cursorPos > binaryOpNode.Token.Span.Lim)
                {
                    // Cursor is after the binary operator. Expected type is equal to the type of left side.
                    expectedNode = binaryOpNode.Left;
                }

                if (expectedNode != null)
                {
                    expectedType = binding.TryGetCoercedType(expectedNode, out coercedType) ? coercedType : binding.GetType(expectedNode);
                    return(true);
                }
            }

            expectedType = DType.Error;
            return(false);
        }
示例#22
0
        public bool IsValidDottedNameNode(DottedNameNode node, TexlBinding binding, OperationCapabilityMetadata metadata, IOpDelegationStrategy opDelStrategy)
        {
            Contracts.AssertValue(node);
            Contracts.AssertValue(binding);
            Contracts.AssertValueOrNull(opDelStrategy);

            var isRowScoped = binding.IsRowScope(node);

            if (!isRowScoped)
            {
                return(IsValidNode(node, binding));
            }

            bool isRowScopedDelegationExempted;

            if (!IsValidRowScopedDottedNameNode(node, binding, metadata, out isRowScopedDelegationExempted))
            {
                var telemetryMessage = string.Format("Kind:{0}, isRowScoped:{1}",
                                                     node.Kind, isRowScoped);

                SuggestDelegationHintAndAddTelemetryMessage(node, binding, telemetryMessage);
                return(false);
            }

            if (isRowScopedDelegationExempted)
            {
                binding.SetBlockScopedConstantNode(node);
                return(true);
            }

            if (binding.TryGetFullRecordRowScopeAccessInfo(node, out var firstNameInfo))
            {
                // This means that this row scoped field is from some parent scope which is non-delegatable. That should deny delegation at that point.
                // For this scope, this means that value will be provided from some other source.
                // For example, AddColumns(CDS As Left, "Column1", LookUp(CDS1, Left.Name in FirstName))
                // CDS - *[Name:s], CDS1 - *[FirstName:s]
                if (GetCapabilityMetadata(firstNameInfo) == null)
                {
                    return(true);
                }
            }

            if (!binding.GetType(node.Left).HasExpandInfo)
            {
                DPath columnPath;
                if (!BinderUtils.TryConvertNodeToDPath(binding, node, out columnPath) || !metadata.IsDelegationSupportedByColumn(columnPath, _function.FunctionDelegationCapability))
                {
                    var safeColumnName = CharacterUtils.MakeSafeForFormatString(columnPath.ToDottedSyntax());
                    var message        = string.Format(StringResources.Get(TexlStrings.OpNotSupportedByColumnSuggestionMessage_OpNotSupportedByColumn), safeColumnName);
                    SuggestDelegationHintAndAddTelemetryMessage(node, binding, message, TexlStrings.OpNotSupportedByColumnSuggestionMessage_OpNotSupportedByColumn, safeColumnName);
                    TrackingProvider.Instance.SetDelegationTrackerStatus(DelegationStatus.NoDelSupportByColumn, node, binding, _function, DelegationTelemetryInfo.CreateNoDelSupportByColumnTelemetryInfo(columnPath.ToDottedSyntax()));
                    return(false);
                }

                // If there is any operator applied on this node then check if column supports operation.
                return(opDelStrategy?.IsOpSupportedByColumn(metadata, node, columnPath, binding) ?? true);
            }

            // If there is an entity reference then we need to do additional verification.
            IExpandInfo info           = binding.GetType(node.Left).ExpandInfo.VerifyValue();
            var         dataSourceInfo = info.ParentDataSource;

            IDataEntityMetadata entityMetadata;

            if (!dataSourceInfo.DataEntityMetadataProvider.TryGetEntityMetadata(info.Identity, out entityMetadata))
            {
                var telemetryMessage = string.Format("Kind:{0}, isRowScoped:{1}, no metadata found for entity {2}",
                                                     node.Kind, isRowScoped, CharacterUtils.MakeSafeForFormatString(info.Identity));

                SuggestDelegationHintAndAddTelemetryMessage(node, binding, telemetryMessage);
                return(false);
            }

            OperationCapabilityMetadata entityCapabilityMetadata = GetScopedOperationCapabilityMetadata(entityMetadata.DelegationMetadata);
            string maybeLogicalName;
            DName  columnName = node.Right.Name;

            if (entityMetadata.DisplayNameMapping.TryGetFromSecond(node.Right.Name.Value, out maybeLogicalName))
            {
                columnName = new DName(maybeLogicalName);
            }

            var entityColumnPath = DPath.Root.Append(columnName);

            if (!entityCapabilityMetadata.IsDelegationSupportedByColumn(entityColumnPath, _function.FunctionDelegationCapability))
            {
                var safeColumnName = CharacterUtils.MakeSafeForFormatString(columnName.Value);
                var message        = string.Format(StringResources.Get(TexlStrings.OpNotSupportedByColumnSuggestionMessage_OpNotSupportedByColumn), safeColumnName);
                SuggestDelegationHintAndAddTelemetryMessage(node, binding, message, TexlStrings.OpNotSupportedByColumnSuggestionMessage_OpNotSupportedByColumn, safeColumnName);
                TrackingProvider.Instance.SetDelegationTrackerStatus(DelegationStatus.NoDelSupportByColumn, node, binding, _function, DelegationTelemetryInfo.CreateNoDelSupportByColumnTelemetryInfo(columnName));
                return(false);
            }

            // If there is any operator applied on this node then check if column supports operation.
            return(opDelStrategy?.IsOpSupportedByColumn(entityCapabilityMetadata, node, entityColumnPath, binding) ?? true);
        }