Exemplo n.º 1
0
        private static void Comparer_VerifyWhere <T>(XArray left, XArray right, CompareOperator cOp) where T : IComparable <T>
        {
            ComparerExtensions.Comparer comparer = TypeProviderFactory.Get(typeof(T).Name).TryGetComparer(cOp);
            BitVector vector = new BitVector(left.Count);

            // Verify 'Set' on an empty set works as expected (normal matches)
            comparer(left, right, vector);
            Comparer_VerifySetMatches <T>(vector, left, right, cOp);
        }
Exemplo n.º 2
0
        public TermExpression(IXTable source, IXColumn left, CompareOperator op, IXColumn right)
        {
            _evaluate = EvaluateNormal;

            // Save arguments as-is for ToString()
            _left  = left;
            _cOp   = op;
            _right = right;

            // Disallow constant <op> constant [likely error not wrapping column name]
            if (_left is ConstantColumn && _right is ConstantColumn)
            {
                throw new ArgumentException($"({left} {op.ToQueryForm()} {right}) is comparing two constants. Wrap [ColumnNames] in braces.");
            }

            // If the left side is a constant and the operator can be swapped, move it to the right side.
            // Comparers can check if the right side is constant and run a faster loop when that's the case.
            if (_left.IsConstantColumn() && !(_right.IsConstantColumn()))
            {
                if (op.TryInvertCompareOperator(out op))
                {
                    _left  = right;
                    _right = left;
                }
            }

            // Disallow unquoted constants used as strings
            if (_right.IsConstantColumn() && _left.ColumnDetails.Type == typeof(String8) && _right.ColumnDetails.Type == typeof(String8))
            {
                ConstantColumn cRight = _right as ConstantColumn;
                if (cRight != null && !cRight.IsNull && cRight.WasUnwrappedLiteral)
                {
                    throw new ArgumentException($"{right} is compared to a string, but is unquoted. Strings must be quoted.");
                }
            }

            // Convert the right side to the left side type if required
            // This means constants will always be casted to the other side type.
            if (_left.ColumnDetails.Type != _right.ColumnDetails.Type)
            {
                _right = CastedColumn.Build(source, _right, _left.ColumnDetails.Type, ValueKinds.Invalid);
            }

            // Get the left and right getters
            _leftGetter  = _left.CurrentGetter();
            _rightGetter = _right.CurrentGetter();

            // Null comparison is generic
            if (_right.IsNullConstant())
            {
                if (op == CompareOperator.Equal)
                {
                    _comparer = WhereIsNull;
                }
                else if (op == CompareOperator.NotEqual)
                {
                    _comparer = WhereIsNotNull;
                }
                else
                {
                    throw new ArgumentException($"Only equals and not equals operators are supported against null.");
                }
            }
            else if (_left.IsNullConstant())
            {
                _left = _right;
                if (op == CompareOperator.Equal)
                {
                    _comparer = WhereIsNull;
                }
                else if (op == CompareOperator.NotEqual)
                {
                    _comparer = WhereIsNotNull;
                }
                else
                {
                    throw new ArgumentException($"Only equals and not equals operators are supported against null.");
                }
            }
            else
            {
                // Get a comparer which can compare the values
                _comparer = TypeProviderFactory.Get(left.ColumnDetails.Type).TryGetComparer(op);
                if (_comparer == null)
                {
                    throw new ArgumentException($"No comparer found for type {left.ColumnDetails.Type.Name}.");
                }
            }

            // Optimize Enum to Constant comparisons to use the underlying indices
            if (_left.IsEnumColumn() && _right.IsConstantColumn())
            {
                // Get an optimized comparer against the indices rather than values
                IXColumn replacedRight = _right;
                _comparer = SetComparer.ConvertToEnumIndexComparer(_left, _comparer, ref replacedRight, source);

                // Get the indices on the left side
                _leftGetter = _left.IndicesCurrentGetter();

                // Use the updated value for the right side
                _rightGetter = replacedRight.CurrentGetter();
            }

            // Allow String8 to constant Contains queries to compare on the raw byte[] and int[]
            if (op == CompareOperator.Contains && _right.IsConstantColumn() && _left.ColumnDetails.Type == typeof(String8) && !_left.IsEnumColumn())
            {
                Func <object> rawGetter = _left.ComponentGetter(ColumnComponent.String8Raw);

                if (rawGetter != null)
                {
                    String8         rightValue      = (String8)_right.ValuesGetter()().Array.GetValue(0);
                    String8Comparer string8Comparer = new String8Comparer();

                    _evaluate = (vector) =>
                    {
                        String8Raw raw = (String8Raw)rawGetter();
                        string8Comparer.WhereContains(raw, rightValue, vector);
                    };
                }
            }
        }
Exemplo n.º 3
0
        /// <summary>
        ///  ConvertToEnumIndexComparer takes a comparer on the values of the enum and translates it to a comparer
        ///  which can operate on the byte[] indices instead.
        /// </summary>
        /// <param name="leftColumn">EnumColumn being compared</param>
        /// <param name="currentComparer">Current Comparison function requested by TermExpression</param>
        /// <param name="rightColumn">Constant being compared against</param>
        /// <param name="source">IXTable containing comparison</param>
        /// <returns>Comparer to compare the (updated) right Constant to the EnumColumn.Indices (rather than Values)</returns>
        public static ComparerExtensions.Comparer ConvertToEnumIndexComparer(IXColumn leftColumn, ComparerExtensions.Comparer currentComparer, ref IXColumn rightColumn, IXTable source)
        {
            Func <XArray> valuesGetter = leftColumn.ValuesGetter();

            if (valuesGetter == null)
            {
                throw new ArgumentException("ConvertToEnumIndexComparer is only valid for columns implementing Values.");
            }

            // Get all distinct values from the left side and find matches
            XArray    left  = leftColumn.ValuesGetter()();
            XArray    right = rightColumn.ValuesGetter()();
            BitVector set   = new BitVector(left.Count);

            currentComparer(left, right, set);

            // NOTE: When EnumColumn values are sorted, can convert comparisons to non-equality native accelerated compare.

            if (set.Count == 0)
            {
                // If there were no matches, always return none
                return(None);
            }
            else if (set.Count == left.Count)
            {
                // If everything matched, always return everything
                return(All);
            }
            else if (set.Count == 1)
            {
                // Convert the constant to the one matching index and make the comparison for index equals that
                rightColumn = new ConstantColumn(source, (byte)set.GetSingle(), typeof(byte));

                return(TypeProviderFactory.Get(typeof(byte)).TryGetComparer(CompareOperator.Equal));
            }
            else if (set.Count == left.Count - 1)
            {
                set.Not(set.Count);

                // Convert the constant to the one non-matching index and make the comparison for index doesn't equal that
                rightColumn = new ConstantColumn(source, (byte)set.GetSingle(), typeof(byte));

                return(TypeProviderFactory.Get(typeof(byte)).TryGetComparer(CompareOperator.NotEqual));
            }
            else
            {
                // Otherwise, build a matcher for values in the set
                return(new SetComparer(set).Evaluate);
            }
        }