protected override SqlPreparedStatement PrepareStatement(IExpressionPreparer preparer, IQueryContext context) { var viewName = context.ResolveTableName(ViewName); var queryFrom = QueryExpressionFrom.Create(context, QueryExpression); var queryPlan = context.DatabaseContext().QueryPlanner().PlanQuery(context, QueryExpression, null); var colList = ColumnNames == null ? new string[0] : ColumnNames.ToArray(); // Wrap the result around a SubsetNode to alias the columns in the // table correctly for this view. int sz = colList.Length; var originalNames = queryFrom.GetResolvedColumns(); var newColumnNames = new ObjectName[originalNames.Length]; if (sz > 0) { if (sz != originalNames.Length) throw new InvalidOperationException("Column list is not the same size as the columns selected."); for (int i = 0; i < sz; ++i) { var colName = colList[i]; newColumnNames[i] = new ObjectName(viewName, colName); } } else { sz = originalNames.Length; for (int i = 0; i < sz; ++i) { newColumnNames[i] = new ObjectName(viewName, originalNames[i].Name); } } // Check there are no repeat column names in the table. for (int i = 0; i < sz; ++i) { var columnName = newColumnNames[i]; for (int n = i + 1; n < sz; ++n) { if (newColumnNames[n].Equals(columnName)) throw new InvalidOperationException(String.Format("Duplicate column name '{0}' in view. A view may not contain duplicate column names.", columnName)); } } // Wrap the plan around a SubsetNode plan queryPlan = new SubsetNode(queryPlan, originalNames, newColumnNames); // We have to execute the plan to get the TableInfo that represents the // result of the view execution. var table = queryPlan.Evaluate(context); var tableInfo = table.TableInfo.Alias(viewName); return new Prepared(tableInfo, QueryExpression, queryPlan, ReplaceIfExists); }