public ITable GetGroupValue(long rowid) { long n = (rowid * 2); // Get the group position and size in the index long groupPos = childGroupsIndex[n]; long groupSize = childGroupsIndex[n + 1]; // Create an interator over this subset of the filter index SubsetRowCursor subset = new SubsetRowCursor(BaseTable.GetRowCursor(), groupPos, groupSize); // Return the table subset SubsetTable groupTable = new SubsetTable(BaseTable, subset); // The subset retains the order of the child groupTable.SetOrderCompositeIsChild(); // Return the group return groupTable; }
private ITable SortFilter(ITable table, FilterExpression expression) { // The filter operation which is a function that describes the sort terms Expression filterExp = expression.Filter; if (!(filterExp is FunctionExpression)) throw new ArgumentException("Expected a function as argument to the filter."); ITable resultTable = table; // If there's something to sort, if (table.RowCount > 1) { // Get the composite function representing the sort collation, FunctionExpression compositeExp = (FunctionExpression) filterExp; if (!compositeExp.Name.Equals("composite")) throw new ArgumentException("Invalid composite function for sorting."); // The natural ordering of the child Expression naturalChildOrder = GetTableOrderComposite(table); if (naturalChildOrder != null) { if (naturalChildOrder.Equals(compositeExp)) // No sort necessary, already sorted return table; // TODO: test for the reverse condition, which we can optimize // with a reverse row iterator. } int paramCount = compositeExp.Parameters.Count; int termCount = paramCount / 2; IIndexSetDataSource rowIndex; bool naturalOrder = true; // If 1 sort term, if (termCount == 1) { Expression sortExp = (Expression) compositeExp.Parameters[0]; naturalOrder = SqlObject.Equals((SqlObject)compositeExp.Parameters[1], SqlObject.True); // Get the index candidate string indexName = sortExp.IndexCandidate; TableName indexTableName = sortExp.IndexTableName; // Index available? rowIndex = GetIndex(table, indexName); } else { // Multiple terms, // Get the index candidate if there is one string indexName = compositeExp.IndexCandidate; TableName indexTableame = compositeExp.IndexTableName; // Index available? rowIndex = GetIndex(table, indexName); } // If we have an index, if (rowIndex != null) { IRowCursor sortedCursor = rowIndex.Select(SelectableRange.Full); if (!naturalOrder) // Reverse iterator, sortedCursor = new ReverseRowCursor(sortedCursor); SubsetTable sortedTable = new SubsetTable(table, sortedCursor); sortedTable.IndexRequestFallthrough = true; // Set the order composite function the describes how the subset is // naturally sorted. sortedTable.OrderComposite = (Expression) compositeExp.Clone(); resultTable = sortedTable; } else { // NOTE: There's lots of directions we can take for optimizing this // sort. For example, if the number of values being sorted meets some // criteria (such as all integers and less than 2 millions values) // then the values being sorted could be read onto the heap and sorted // in memory with a quick sort. // Scan sort, // The working set, IIndex<RowId> workingSet = transaction.CreateTemporaryIndex<RowId>(table.RowCount); // Create the resolver IndexResolver resolver = CreateResolver(table, compositeExp); // Iterator over the source table IRowCursor tableCursor = table.GetRowCursor(); // Wrap in a forward prefetch iterator tableCursor = new PrefetchRowCursor(tableCursor, table); // Use a buffer, RowId[] rowIds = new RowId[128]; while (tableCursor.MoveNext()) { int count = 0; while (tableCursor.MoveNext() && count < 128) { rowIds[count] = tableCursor.Current; ++count; } for (int i = 0; i < count; ++i) { RowId rowid = rowIds[i]; // Get the value, SqlObject[] values = resolver.GetValue(rowid); // Insert the record into sorted order in the working_set workingSet.Insert(values, rowid, resolver); } } // TODO: record 'workingSet' for future resolution. // The result, IRowCursor sortedCursor = new DefaultRowCursor(workingSet.GetCursor()); SubsetTable sortedTable = new SubsetTable(table, sortedCursor); sortedTable.IndexRequestFallthrough = true; // Set the order composite function the describes how the subset is // naturally sorted. sortedTable.OrderComposite = (Expression) compositeExp.Clone(); resultTable = sortedTable; } } return resultTable; }
private SubsetTable FilterByIndex(ITable table, IIndexSetDataSource index, Expression order, SelectableRange range) { // Select from the index and return the subset IRowCursor rows = index.Select(range); SubsetTable filteredTable = new SubsetTable(table, rows); filteredTable.OrderComposite = order; // If the number of rows selected from the index is the same as the // original table, then it is safe for index requests to fallthrough to the // parent. long selectCount = rows.Count; long originalCount = table.RowCount; if (selectCount == originalCount) filteredTable.IndexRequestFallthrough = true; // Assert we didn't select more than in the original context if (selectCount > originalCount) throw new ApplicationException( "Index found more values than in parent table."); return filteredTable; }
internal ITable FilterByScan(ITable table, Expression op) { // Default is to match table, ITable resultTable = table; long rowCount = table.RowCount; // If the table is not empty, if (rowCount > 0) { // Put the table on the stack, PushTable(table); // The working set, IIndex<RowId> workingSet = transaction.CreateTemporaryIndex<RowId>(rowCount); // TODO: Common expression scans should be optimized // Default scan (works for everything) // Fetch the table's row iterator IRowCursor cursor = table.GetRowCursor(); // Wrap in a forward prefetch iterator cursor = new PrefetchRowCursor(cursor, table); // True if all matched bool allMatched = true; // For each value, while (cursor.MoveNext()) { // Fetch the next row_id from the iterator RowId rowid = cursor.Current; // Set the top of stack table row_id UpdateTableRow(rowid); // Execute the expression, ITable expResult = DoExecute(op); // If it's true, add the row_id to the working set if (BooleanResult(expResult)) { // Note, we preserve the ordering of the table being filtered workingSet.Add(rowid); } else { // Wasn't a true result, so we didn't all match. allMatched = false; } } // If we matched nothing if (workingSet.Count == 0) { // Return a subset of the given table that is empty SubsetTable subsetTable = new SubsetTable(table); // We inherit the order composite description from the child. subsetTable.SetOrderCompositeIsChild(); resultTable = subsetTable; } // If we matched something else { // If all matched we return the table if (allMatched) { // Clear the working set and set the result table workingSet.Clear(); resultTable = table; } else { // Something in working set, and we didn't match everything, IRowCursor setCursor = new DefaultRowCursor(workingSet.GetCursor()); SubsetTable subsetTable = new SubsetTable(table, setCursor); // We inherit the order composite description from the child. subsetTable.SetOrderCompositeIsChild(); resultTable = subsetTable; } } // Pop the current table from the stack PopTable(); } return resultTable; }