} // getMainSchemaName() public override DataSet materializeMainSchemaTable(Table table, Column[] columns, int maxRows) { DocumentConverter documentConverter = _schemaBuilder.getDocumentConverter(table); SelectItem[] selectItems = MetaModelHelper.createSelectItems(columns); DataSetHeader header = new CachingDataSetHeader(selectItems); DocumentSource documentSource = getDocumentSourceForTable(table.getName()); DataSet dataSet = new DocumentSourceDataSet(header, documentSource, documentConverter); if (maxRows > 0) { dataSet = new MaxRowsDataSet(dataSet, maxRows); } return(dataSet); } // materializeMainSchemaTable()
} // getCarthesianProduct() #endregion getCarthesianProduct() /** * Executes a simple nested loop join. The innerLoopDs will be copied in an * in-memory dataset. * */ public static InMemoryDataSet nestedLoopJoin(DataSet innerLoopDs, DataSet outerLoopDs, IEnumerable <FilterItem> filtersIterable) { List <FilterItem> filters = new List <FilterItem>(); foreach (FilterItem fi in filtersIterable) { filters.Add(fi); } List <Row> innerRows = innerLoopDs.toRows(); List <SelectItem> allItems = new List <SelectItem>(NArrays.AsList <SelectItem>(outerLoopDs.getSelectItems())); allItems.AddRange(NArrays.AsList(innerLoopDs.getSelectItems())); HashSet <FilterItem> applicable_filters = applicableFilters(filters, allItems); DataSetHeader jointHeader = new CachingDataSetHeader(allItems); List <Row> resultRows = new List <Row>(); foreach (Row outerRow in outerLoopDs) { foreach (Row innerRow in innerRows) { Object[] joinedRowObjects = new Object[outerRow.getValues().Length + innerRow.getValues().Length]; Array.Copy(outerRow.getValues(), 0, joinedRowObjects, 0, outerRow.getValues().Length); Array.Copy(innerRow.getValues(), 0, joinedRowObjects, outerRow.getValues().Length, innerRow.getValues().Length); Row joinedRow = new DefaultRow(jointHeader, joinedRowObjects); IEnumerable <FilterItem> selected_items = applicable_filters.Where(fi => isJoinedRowAccepted(fi, joinedRow)); if (applicable_filters.IsEmpty() || (selected_items != null && selected_items.Count <FilterItem>() != 0)) { resultRows.Add(joinedRow); } } } return(new InMemoryDataSet(jointHeader, resultRows)); } // nestedLoopJoin()
} // getGrouped() /** * Applies aggregate values to a dataset. This method is to be invoked AFTER * any filters have been applied. * * @param workSelectItems * all select items included in the processing of the query * (including those originating from other clauses than the * SELECT clause). * @param dataSet * @return */ public static DataSet getAggregated(List <SelectItem> workSelectItems, DataSet dataSet) { List <SelectItem> functionItems = getAggregateFunctionSelectItems(workSelectItems); if (functionItems.IsEmpty()) { return(dataSet); } AggregateBuilder <Object> t; Dictionary <SelectItem, AggregateBuilder <Object> > aggregateBuilders = new Dictionary <SelectItem, AggregateBuilder <Object> >(); foreach (SelectItem item in functionItems) { aggregateBuilders.Add(item, item.getAggregateFunction().createAggregateBuilder <object>()); } DataSetHeader header; bool onlyAggregates; if (functionItems.Count != workSelectItems.Count) { onlyAggregates = false; header = new CachingDataSetHeader(workSelectItems); } else { onlyAggregates = true; header = new SimpleDataSetHeader(workSelectItems); } List <Row> resultRows = new List <Row>(); while (dataSet.next()) { Row inputRow = dataSet.getRow(); foreach (SelectItem item in functionItems) { AggregateBuilder <object> aggregateBuilder = aggregateBuilders[item]; Column column = item.getColumn(); if (column != null) { Object value = inputRow.getValue(new SelectItem(column)); aggregateBuilder.add(value); } else if (SelectItem.isCountAllItem(item)) { // Just use the empty string, since COUNT(*) don't // evaluate values (but null values should be prevented) aggregateBuilder.add(""); } else { throw new ArgumentException("Expression function not supported: " + item); } } // If the result should also contain non-aggregated values, we // will keep those in the rows list if (!onlyAggregates) { Object[] values = new Object[header.size()]; for (int i = 0; i < header.size(); i++) { Object value = inputRow.getValue(header.getSelectItem(i)); if (value != null) { values[i] = value; } } resultRows.Add(new DefaultRow(header, values)); } } dataSet.close(); // Collect the aggregates Dictionary <SelectItem, Object> functionResult = new Dictionary <SelectItem, Object>(); foreach (SelectItem item in functionItems) { AggregateBuilder <object> aggregateBuilder = aggregateBuilders[item]; Object result = aggregateBuilder.getAggregate(); functionResult.Add(item, result); } // if there are no result rows (no matching records at all), we still // need to return a record with the aggregates bool noResultRows = resultRows.IsEmpty(); if (onlyAggregates || noResultRows) { // We will only create a single row with all the aggregates Object[] values = new Object[header.size()]; for (int i = 0; i < header.size(); i++) { values[i] = functionResult[header.getSelectItem(i)]; } Row row = new DefaultRow(header, values); resultRows.Add(row); } else { // We will create the aggregates as well as regular values for (int i = 0; i < resultRows.Count; i++) { Row row = resultRows[i]; Object[] values = row.getValues(); foreach (KeyValuePair <SelectItem, Object> entry in functionResult) { SelectItem item = entry.Key; int itemIndex = row.indexOf(item); if (itemIndex != -1) { Object value = entry.Value; values[itemIndex] = value; } } resultRows[i] = new DefaultRow(header, values); } } return(new InMemoryDataSet(header, resultRows)); } // getAggregated()
} // getGrouped() public static DataSet getGrouped(List <SelectItem> selectItems, DataSet dataSet, GroupByItem[] groupByItems) { DataSet result = dataSet; if (groupByItems != null && groupByItems.Length > 0) { Dictionary <Row, Dictionary <SelectItem, List <Object> > > uniqueRows = new Dictionary <Row, Dictionary <SelectItem, List <Object> > >(); SelectItem[] groupBySelects = new SelectItem[groupByItems.Length]; for (int i = 0; i < groupBySelects.Length; i++) { groupBySelects[i] = groupByItems[i].getSelectItem(); } DataSetHeader groupByHeader = new CachingDataSetHeader(groupBySelects); // Creates a list of SelectItems that have aggregate functions List <SelectItem> functionItems = getAggregateFunctionSelectItems(selectItems); // Loop through the dataset and identify groups while (dataSet.next()) { Row row = dataSet.getRow(); // Subselect a row prototype with only the unique values that // define the group Row uniqueRow = row.getSubSelection(groupByHeader); // function input is the values used for calculating aggregate // functions in the group Dictionary <SelectItem, List <Object> > functionInput; if (!uniqueRows.ContainsKey(uniqueRow)) { // If this group already exist, use an existing function // input functionInput = new Dictionary <SelectItem, List <Object> >(); foreach (SelectItem item in functionItems) { functionInput.Add(item, new List <Object>()); } uniqueRows.Add(uniqueRow, functionInput); } else { // If this is a new group, create a new function input functionInput = uniqueRows[uniqueRow]; } // Loop through aggregate functions to check for validity foreach (SelectItem item in functionItems) { List <Object> objects = functionInput[item]; Column column = item.getColumn(); if (column != null) { Object value = row.getValue(new SelectItem(column)); objects.Add(value); } else if (SelectItem.isCountAllItem(item)) { // Just use the empty string, since COUNT(*) don't // evaluate values (but null values should be prevented) objects.Add(""); } else { throw new ArgumentException("Expression function not supported: " + item); } } } dataSet.close(); List <Row> resultData = new List <Row>(); DataSetHeader resultHeader = new CachingDataSetHeader(selectItems); int count = uniqueRows.Count; // Loop through the groups to generate aggregates foreach (KeyValuePair <Row, Dictionary <SelectItem, List <Object> > > key_value in uniqueRows) { Row row = key_value.Key; Dictionary <SelectItem, List <Object> > functionInput = key_value.Value; Object[] resultRow = new Object[selectItems.Count]; // Loop through select items to generate a row int i = 0; foreach (SelectItem item in selectItems) { int uniqueRowIndex = row.indexOf(item); if (uniqueRowIndex != -1) { // If there's already a value for the select item in the // row, keep it (it's one of the grouped by columns) resultRow[i] = row.getValue(uniqueRowIndex); } else { // Use the function input to calculate the aggregate // value List <Object> objects = functionInput[item]; if (objects != null) { Object functionResult = item.getAggregateFunction().evaluate(objects.ToArray()); resultRow[i] = functionResult; } else { if (item.getAggregateFunction() != null) { logger.error("No function input found for SelectItem: {}", item); } } } i++; } resultData.Add(new DefaultRow(resultHeader, resultRow, null)); } if (resultData.IsEmpty()) { result = new EmptyDataSet(selectItems); } else { result = new InMemoryDataSet(resultHeader, resultData); } } result = getSelection(selectItems, result); return(result); } // getGrouped()
} // containsNonSelectScalaFunctions() /** * Performs a left join (aka left outer join) operation on two datasets. * * @param ds1 * the left dataset * @param ds2 * the right dataset * @param onConditions * the conditions to join by * @return the left joined result dataset */ public static DataSet getLeftJoin(DataSet ds1, DataSet ds2, FilterItem[] onConditions) { if (ds1 == null) { throw new ArgumentException("Left DataSet cannot be null"); } if (ds2 == null) { throw new ArgumentException("Right DataSet cannot be null"); } SelectItem[] si1 = ds1.getSelectItems(); SelectItem[] si2 = ds2.getSelectItems(); SelectItem[] selectItems = new SelectItem[si1.Length + si2.Length]; Array.Copy(si1, 0, selectItems, 0, si1.Length); Array.Copy(si2, 0, selectItems, si1.Length, si2.Length); List <Row> resultRows = new List <Row>(); List <Row> ds2data = readDataSetFull(ds2); if (ds2data.IsEmpty()) { // no need to join, simply return a new view (with null values) on // the previous dataset. return(getSelection(selectItems, ds1)); } DataSetHeader header = new CachingDataSetHeader(selectItems); while (ds1.next()) { // Construct a single-row dataset for making a carthesian product // against ds2 Row ds1row = ds1.getRow(); List <Row> ds1rows = new List <Row>(); ds1rows.Add(ds1row); DataSet carthesianProduct = getCarthesianProduct(new DataSet[] { new InMemoryDataSet( new CachingDataSetHeader(si1), ds1rows), new InMemoryDataSet(new CachingDataSetHeader(si2), ds2data) }, onConditions); List <Row> carthesianRows = readDataSetFull(carthesianProduct); if (carthesianRows.Count > 0) { resultRows.AddRange(carthesianRows); } else { Object[] values = ds1row.getValues(); Object[] row = new Object[selectItems.Length]; Array.Copy(values, 0, row, 0, values.Length); resultRows.Add(new DefaultRow(header, row)); } } ds1.close(); if (resultRows.IsEmpty()) { return(new EmptyDataSet(selectItems)); } return(new InMemoryDataSet(header, resultRows)); } // getLeftJoin()