String msg = String.format("A materialized view (%s) can not be defined on another view (%s).",
viewName, srcTable.getTypeName());
throw m_compiler.new VoltCompilerException(msg);
}
MaterializedViewInfo matviewinfo = srcTable.getViews().add(viewName);
matviewinfo.setDest(destTable);
AbstractExpression where = stmt.getSingleTableFilterExpression();
if (where != null) {
String hex = Encoder.hexEncode(where.toJSONString());
matviewinfo.setPredicate(hex);
} else {
matviewinfo.setPredicate("");
}
destTable.setMaterializer(srcTable);
List<Column> srcColumnArray = CatalogUtil.getSortedCatalogItems(srcTable.getColumns(), "index");
List<Column> destColumnArray = CatalogUtil.getSortedCatalogItems(destTable.getColumns(), "index");
List<AbstractExpression> groupbyExprs = null;
if (stmt.hasComplexGroupby()) {
groupbyExprs = new ArrayList<AbstractExpression>();
for (ParsedColInfo col: stmt.m_groupByColumns) {
groupbyExprs.add(col.expression);
}
// Parse group by expressions to json string
String groupbyExprsJson = null;
try {
groupbyExprsJson = convertToJSONArray(groupbyExprs);
} catch (JSONException e) {
throw m_compiler.new VoltCompilerException ("Unexpected error serializing non-column " +
"expressions for group by expressions: " + e.toString());
}
matviewinfo.setGroupbyexpressionsjson(groupbyExprsJson);
} else {
// add the group by columns from the src table
for (int i = 0; i < stmt.m_groupByColumns.size(); i++) {
ParsedSelectStmt.ParsedColInfo gbcol = stmt.m_groupByColumns.get(i);
Column srcCol = srcColumnArray.get(gbcol.index);
ColumnRef cref = matviewinfo.getGroupbycols().add(srcCol.getTypeName());
// groupByColumns is iterating in order of groups. Store that grouping order
// in the column ref index. When the catalog is serialized, it will, naturally,
// scramble this order like a two year playing dominos, presenting the data
// in a meaningless sequence.
cref.setIndex(i); // the column offset in the view's grouping order
cref.setColumn(srcCol); // the source column from the base (non-view) table
}
// parse out the group by columns into the dest table
for (int i = 0; i < stmt.m_groupByColumns.size(); i++) {
ParsedSelectStmt.ParsedColInfo col = stmt.m_displayColumns.get(i);
Column destColumn = destColumnArray.get(i);
processMaterializedViewColumn(matviewinfo, srcTable, destColumn,
ExpressionType.VALUE_TUPLE, (TupleValueExpression)col.expression);
}
}
// Set up COUNT(*) column
ParsedSelectStmt.ParsedColInfo countCol = stmt.m_displayColumns.get(stmt.m_groupByColumns.size());
assert(countCol.expression.getExpressionType() == ExpressionType.AGGREGATE_COUNT_STAR);
assert(countCol.expression.getLeft() == null);
processMaterializedViewColumn(matviewinfo, srcTable,
destColumnArray.get(stmt.m_groupByColumns.size()),
ExpressionType.AGGREGATE_COUNT_STAR, null);
// create an index and constraint for the table
Index pkIndex = destTable.getIndexes().add(HSQLInterface.AUTO_GEN_MATVIEW_IDX);
pkIndex.setType(IndexType.BALANCED_TREE.getValue());
pkIndex.setUnique(true);
// add the group by columns from the src table
// assume index 1 throuh #grpByCols + 1 are the cols
for (int i = 0; i < stmt.m_groupByColumns.size(); i++) {
ColumnRef c = pkIndex.getColumns().add(String.valueOf(i));
c.setColumn(destColumnArray.get(i));
c.setIndex(i);
}
Constraint pkConstraint = destTable.getConstraints().add(HSQLInterface.AUTO_GEN_MATVIEW_CONST);
pkConstraint.setType(ConstraintType.PRIMARY_KEY.getValue());
pkConstraint.setIndex(pkIndex);
// prepare info for aggregation columns.
List<AbstractExpression> aggregationExprs = new ArrayList<AbstractExpression>();
boolean hasAggregationExprs = false;
boolean hasMinOrMaxAgg = false;
ArrayList<AbstractExpression> minMaxAggs = new ArrayList<AbstractExpression>();
for (int i = stmt.m_groupByColumns.size() + 1; i < stmt.m_displayColumns.size(); i++) {
ParsedSelectStmt.ParsedColInfo col = stmt.m_displayColumns.get(i);
AbstractExpression aggExpr = col.expression.getLeft();
if (aggExpr.getExpressionType() != ExpressionType.VALUE_TUPLE) {
hasAggregationExprs = true;
}
aggregationExprs.add(aggExpr);
if (col.expression.getExpressionType() == ExpressionType.AGGREGATE_MIN ||
col.expression.getExpressionType() == ExpressionType.AGGREGATE_MAX) {
hasMinOrMaxAgg = true;
minMaxAggs.add(aggExpr);
}
}
// set Aggregation Expressions.
if (hasAggregationExprs) {
String aggregationExprsJson = null;
try {
aggregationExprsJson = convertToJSONArray(aggregationExprs);
} catch (JSONException e) {
throw m_compiler.new VoltCompilerException ("Unexpected error serializing non-column " +
"expressions for aggregation expressions: " + e.toString());
}
matviewinfo.setAggregationexpressionsjson(aggregationExprsJson);
}
if (hasMinOrMaxAgg) {
// TODO: deal with minMaxAggs, i.e. if only one min/max agg, try to find the index
// with group by cols followed by this agg col; if multiple min/max aggs, decide
// what to do (probably the index on group by cols is the best choice)
Index found = findBestMatchIndexForMatviewMinOrMax(matviewinfo, srcTable, groupbyExprs);
if (found != null) {
matviewinfo.setIndexforminmax(found.getTypeName());
} else {
matviewinfo.setIndexforminmax("");
m_compiler.addWarn("No index found to support min() / max() UPDATE and DELETE on Materialized View " +
matviewinfo.getTypeName() +
", and a sequential scan might be issued when current min / max value is updated / deleted.");
}
} else {
matviewinfo.setIndexforminmax("");
}
// parse out the aggregation columns into the dest table
for (int i = stmt.m_groupByColumns.size() + 1; i < stmt.m_displayColumns.size(); i++) {
ParsedSelectStmt.ParsedColInfo col = stmt.m_displayColumns.get(i);