} // constructor public DataSet executeQuery(Query query) { List <SelectItem> selectItems = query.getSelectClause().getItems(); List <FromItem> fromItems = query.getFromClause().getItems(); List <FilterItem> whereItems = query.getWhereClause().getItems(); List <SelectItem> whereSelectItems = query.getWhereClause().getEvaluatedSelectItems(); List <GroupByItem> groupByItems = query.getGroupByClause().getItems(); List <SelectItem> groupBySelectItems = query.getGroupByClause().getEvaluatedSelectItems(); List <SelectItem> havingSelectItems = query.getHavingClause().getEvaluatedSelectItems(); List <SelectItem> orderBySelectItems = query.getOrderByClause().getEvaluatedSelectItems(); List <FilterItem> havingItems = query.getHavingClause().getItems(); List <OrderByItem> orderByItems = query.getOrderByClause().getItems(); int firstRow = (query.getFirstRow() == null ? 1 : query.getFirstRow()); int maxRows = (query.getMaxRows() == null ? -1 : query.getMaxRows()); if (maxRows == 0) { // no rows requested - no reason to do anything return(new EmptyDataSet(selectItems)); } // check certain common query types that can often be optimized by // subclasses bool singleFromItem = fromItems.Count == 1; bool noGrouping = groupByItems.IsEmpty() && havingItems.IsEmpty(); if (singleFromItem && noGrouping) { FromItem fromItem = query.getFromClause().getItem(0); Table table = fromItem.getTable(); if (table != null) { // check for SELECT COUNT(*) queries if (selectItems.Count == 1) { SelectItem selectItem = query.getSelectClause().getItem(0); if (SelectItem.isCountAllItem(selectItem)) { bool functionApproximationAllowed = selectItem.isFunctionApproximationAllowed(); if (isMainSchemaTable(table)) { logger.debug("Query is a COUNT query with {} where items. Trying executeCountQuery(...)", whereItems.Count); NNumber count = executeCountQuery(table, whereItems, functionApproximationAllowed); if (count == null) { logger.debug( "DataContext did not return any count query results. Proceeding with manual counting."); } else { List <Row> data = new List <Row>(1); DataSetHeader header = new SimpleDataSetHeader(new SelectItem[] { selectItem }); data.Add(new DefaultRow(header, new Object[] { count })); return(new InMemoryDataSet(header, data)); } } } } bool is_simple_select = isSimpleSelect(query.getSelectClause()); if (is_simple_select) { // check for lookup query by primary key if (whereItems.Count == 1) { FilterItem whereItem = whereItems[0]; SelectItem selectItem = whereItem.getSelectItem(); if (!whereItem.isCompoundFilter() && selectItem != null && selectItem.getColumn() != null) { Column column = selectItem.getColumn(); if (column.isPrimaryKey() && OperatorType.EQUALS_TO.Equals(whereItem.getOperator())) { logger.debug( "Query is a primary key lookup query. Trying executePrimaryKeyLookupQuery(...)"); if (table != null) { if (isMainSchemaTable(table)) { Object operand = whereItem.getOperand(); Row row = executePrimaryKeyLookupQuery(table, selectItems, column, operand); if (row == null) { logger.debug( "DataContext did not return any GET query results. Proceeding with manual lookup."); } else { DataSetHeader header = new SimpleDataSetHeader(selectItems); return(new InMemoryDataSet(header, row)); } } } } } } // check for simple queries with or without simple criteria if (orderByItems.IsEmpty()) { DataSet ds = null; // no WHERE criteria set if (whereItems.IsEmpty()) { ds = materializeTable(table, selectItems, firstRow, maxRows); return(ds); } ds = materializeTable(table, selectItems, whereItems, firstRow, maxRows); return(ds); } } } } // Creates a list for all select items that are needed to execute query // (some may only be used as part of a filter, but not shown in result) List <SelectItem> workSelectItems = CollectionUtils.concat(true, selectItems, whereSelectItems, groupBySelectItems, havingSelectItems, orderBySelectItems); // Materialize the tables in the from clause DataSet[] fromDataSets = new DataSet[fromItems.Count]; for (int i = 0; i < fromDataSets.Length; i++) { FromItem fromItem = fromItems[i]; fromDataSets[i] = materializeFromItem(fromItem, workSelectItems); } // Execute the query using the raw data DataSet dataSet = null; // MetaModelHelper.getCarthesianProduct(fromDataSets, whereItems); // we can now exclude the select items imposed by the WHERE clause (and // should, to make the aggregation process faster) workSelectItems = CollectionUtils.concat(true, selectItems, groupBySelectItems, havingSelectItems, orderBySelectItems); if (groupByItems.Count > 0) { dataSet = MetaModelHelper.getGrouped(workSelectItems, dataSet, groupByItems); } else { dataSet = MetaModelHelper.getAggregated(workSelectItems, dataSet); } dataSet = MetaModelHelper.getFiltered(dataSet, havingItems); if (query.getSelectClause().isDistinct()) { dataSet = MetaModelHelper.getSelection(selectItems, dataSet); dataSet = MetaModelHelper.getDistinct(dataSet); dataSet = MetaModelHelper.getOrdered(dataSet, orderByItems); } else { dataSet = MetaModelHelper.getOrdered(dataSet, orderByItems); dataSet = MetaModelHelper.getSelection(selectItems, dataSet); } dataSet = MetaModelHelper.getPaged(dataSet, firstRow, maxRows); return(dataSet); } // executeQuery()
} // getInformationSchema() public virtual DataSet materializeInformationSchemaTable(Table table, List <SelectItem> selectItems) { String tableName = table.getName(); SelectItem[] columnSelectItems = MetaModelHelper.createSelectItems(table.getColumns()); SimpleDataSetHeader header = new SimpleDataSetHeader(columnSelectItems); Table[] tables = getDefaultSchema().getTables(false); List <Row> data = new List <Row>(); if ("tables".Equals(tableName)) { // "tables" columns: name, type, num_columns, remarks foreach (Table t in tables) { String typeString = null; if (t.GetType() != null) { typeString = t.getType().ToString(); } data.Add(new DefaultRow(header, new Object[] { t.getName(), typeString, t.getColumnCount(), t.getRemarks() })); } } else if ("columns".Equals(tableName)) { // "columns" columns: name, type, native_type, size, nullable, // indexed, table, remarks foreach (Table t in tables) { foreach (Column c in t.getColumns()) { String typeString = null; if (t.GetType() != null) { typeString = c.getType().ToString(); } data.Add(new DefaultRow(header, new Object[] { c.getName(), typeString, c.getNativeType(), c.getColumnSize(), c.isNullable(), c.isIndexed(), t.getName(), c.getRemarks() })); } } } else if ("relationships".Equals(tableName)) { // "relationships" columns: primary_table, primary_column, // foreign_table, foreign_column foreach (Relationship r in getDefaultSchema().getRelationships()) { Column[] primaryColumns = r.getPrimaryColumns(); Column[] foreignColumns = r.getForeignColumns(); Table pTable = r.getPrimaryTable(); Table fTable = r.getForeignTable(); for (int i = 0; i < primaryColumns.Length; i++) { Column pColumn = primaryColumns[i]; Column fColumn = foreignColumns[i]; data.Add(new DefaultRow(header, new Object[] { pTable.getName(), pColumn.getName(), fTable.getName(), fColumn.getName() })); } } } else { throw new ArgumentException("Cannot materialize non information_schema table: " + table); } DataSet dataSet; if (data.IsEmpty()) { dataSet = new EmptyDataSet(selectItems); } else { dataSet = new InMemoryDataSet(header, data); } // Handle column subset DataSet selectionDataSet = MetaModelHelper.getSelection(selectItems, dataSet); dataSet = selectionDataSet; return(dataSet); } // materializeInformationSchemaTable()
} // 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()