Ejemplo n.º 1
0
        public static ITable All(this ITable table, IQueryContext context, Expression expression, Operator op, ITable other)
        {
            // Check the table only has 1 column
            if (other.TableInfo.ColumnCount != 1)
            {
                throw new ApplicationException("Input table <> 1 columns.");
            }

            // Handle trivial case of no entries to select from
            if (table.RowCount == 0)
            {
                return(table);
            }

            var theTable = table as Table;

            if (theTable == null)
            {
                return(table);
            }

            // If 'table' is empty then we return the complete set.  ALL { empty set }
            // is always true.
            if (other.RowCount == 0)
            {
                return(table);
            }

            // Is the lhs expression a constant?
            if (expression.IsConstant())
            {
                // We know lhs is a constant so no point passing arguments,
                DataObject value = expression.Evaluate(context);
                bool       comparedToTrue;

                // The various operators
                if (op.IsEquivalent(Operator.Greater) ||
                    op.IsEquivalent(Operator.GreaterOrEqual))
                {
                    // Find the maximum value in the table
                    DataObject cell = other.GetLastCell(0);
                    comparedToTrue = CompareCells(value, cell, op);
                }
                else if (op.IsEquivalent(Operator.Smaller) ||
                         op.IsEquivalent(Operator.SmallerOrEqual))
                {
                    // Find the minimum value in the table
                    DataObject cell = other.GetFirstCell(0);
                    comparedToTrue = CompareCells(value, cell, op);
                }
                else if (op.IsEquivalent(Operator.Equal))
                {
                    // Only true if rhs is a single value
                    DataObject cell = other.GetSingleCell(0);
                    comparedToTrue = (cell != null && CompareCells(value, cell, op));
                }
                else if (op.IsEquivalent(Operator.NotEqual))
                {
                    // true only if lhs_cell is not found in column.
                    comparedToTrue = !other.ColumnContainsValue(0, value);
                }
                else
                {
                    throw new ApplicationException("Don't understand operator '" + op + "' in ALL.");
                }

                // If matched return this table
                if (comparedToTrue)
                {
                    return(table);
                }

                // No entries matches so return an empty table.
                return(table.EmptySelect());
            }

            Table sourceTable;
            int   colIndex;
            // Is the lhs expression a single variable?
            ObjectName expVar = expression.AsVariable();

            // NOTE: It'll be less common for this part to be called.
            if (expVar == null)
            {
                // This is a complex expression so make a FunctionTable as our new
                // source.
                DatabaseQueryContext dbContext = (DatabaseQueryContext)context;
                FunctionTable        funTable  = new FunctionTable((Table)table, new[] { expression }, new [] { "1" }, dbContext);
                sourceTable = funTable;
                colIndex    = 0;
            }
            else
            {
                // The expression is an easy to resolve reference in this table.
                sourceTable = (Table)table;

                colIndex = sourceTable.FindFieldName(expVar);
                if (colIndex == -1)
                {
                    throw new ApplicationException("Can't find column '" + expVar + "'.");
                }
            }

            // Check that the first column of 'table' is of a compatible type with
            // source table column (lhs_col_index).
            // ISSUE: Should we convert to the correct type via a FunctionTable?
            DataColumnInfo sourceCol = sourceTable.TableInfo[colIndex];
            DataColumnInfo destCol   = other.TableInfo[0];

            if (!sourceCol.DataType.IsComparable(destCol.DataType))
            {
                throw new ApplicationException("The type of the sub-query expression " +
                                               sourceCol.DataType + " is incompatible " +
                                               "with the sub-query " + destCol.DataType +
                                               ".");
            }

            // We now have all the information to solve this query.
            // We work output as follows:
            //   For >, >= type ALL we find the highest value in 'table' and
            //   select from 'source' all the rows that are >, >= than the
            //   highest value.
            //   For <, <= type ALL we find the lowest value in 'table' and
            //   select from 'source' all the rows that are <, <= than the
            //   lowest value.
            //   For = type ALL we see if 'table' contains a single value.  If it
            //   does we select all from 'source' that equals the value, otherwise an
            //   empty table.
            //   For <> type ALL we use the 'not in' algorithm.

            IList <long> selectList;

            if (op.IsEquivalent(Operator.Greater) ||
                op.IsEquivalent(Operator.GreaterOrEqual))
            {
                // Select the last from the set (the highest value),
                DataObject highestCell = other.GetLastCell(0);
                // Select from the source table all rows that are > or >= to the
                // highest cell,
                selectList = sourceTable.SelectRows(colIndex, op, highestCell).ToList();
            }
            else if (op.IsEquivalent(Operator.Smaller) ||
                     op.IsEquivalent(Operator.SmallerOrEqual))
            {
                // Select the first from the set (the lowest value),
                DataObject lowestCell = other.GetFirstCell(0);
                // Select from the source table all rows that are < or <= to the
                // lowest cell,
                selectList = sourceTable.SelectRows(colIndex, op, lowestCell).ToList();
            }
            else if (op.IsEquivalent(Operator.Equal))
            {
                // Select the single value from the set (if there is one).
                DataObject singleCell = other.GetSingleCell(0);
                if (singleCell != null)
                {
                    // Select all from source_table all values that = this cell
                    selectList = sourceTable.SelectRows(colIndex, op, singleCell).ToList();
                }
                else
                {
                    // No single value so return empty set (no value in LHS will equal
                    // a value in RHS).
                    return(table.EmptySelect());
                }
            }
            else if (op.IsEquivalent(Operator.NotEqual))
            {
                // Equiv. to NOT IN
                selectList = sourceTable.NotIn(other, colIndex, 0).ToList();
            }
            else
            {
                throw new ApplicationException("Don't understand operator '" + op + "' in ALL.");
            }

            // Make into a table to return.
            VirtualTable rtable = new VirtualTable(theTable);

            rtable.Set((Table)table, selectList);
            return(rtable);
        }