DeveelDB  20151217
complete SQL database system, primarly developed for .NET/Mono frameworks
CreateViewStatement.cs
Go to the documentation of this file.
1 //
2 // Copyright 2010-2015 Deveel
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 
17 using System;
18 using System.Collections.Generic;
19 using System.IO;
20 using System.Linq;
21 
24 using Deveel.Data.Sql.Query;
25 using Deveel.Data.Sql.Tables;
26 using Deveel.Data.Sql.Views;
27 
28 namespace Deveel.Data.Sql.Statements {
30  public CreateViewStatement(string viewName, SqlQueryExpression queryExpression)
31  : this(viewName, null, queryExpression) {
32  }
33 
34  public CreateViewStatement(string viewName, IEnumerable<string> columnNames, SqlQueryExpression queryExpression) {
35  if (viewName == null)
36  throw new ArgumentNullException("viewName");
37  if (queryExpression == null)
38  throw new ArgumentNullException("queryExpression");
39 
40  ViewName = viewName;
41  ColumnNames = columnNames;
42  QueryExpression = queryExpression;
43  }
44 
45  public string ViewName { get; private set; }
46 
47  public IEnumerable<string> ColumnNames { get; private set; }
48 
49  public SqlQueryExpression QueryExpression { get; private set; }
50 
51  public bool ReplaceIfExists { get; set; }
52 
54  var viewName = context.Query.ResolveTableName(ViewName);
55 
56  var queryFrom = QueryExpressionFrom.Create(context, QueryExpression);
57  var queryPlan = context.Query.Context.QueryPlanner().PlanQuery(new QueryInfo(context, QueryExpression));
58 
59  var colList = ColumnNames == null ? new string[0] : ColumnNames.ToArray();
60 
61  // Wrap the result around a SubsetNode to alias the columns in the
62  // table correctly for this view.
63  int sz = colList.Length;
64  var originalNames = queryFrom.GetResolvedColumns();
65  var newColumnNames = new ObjectName[originalNames.Length];
66 
67  if (sz > 0) {
68  if (sz != originalNames.Length)
69  throw new InvalidOperationException("Column list is not the same size as the columns selected.");
70 
71  for (int i = 0; i < sz; ++i) {
72  var colName = colList[i];
73  newColumnNames[i] = new ObjectName(viewName, colName);
74  }
75  } else {
76  sz = originalNames.Length;
77  for (int i = 0; i < sz; ++i) {
78  newColumnNames[i] = new ObjectName(viewName, originalNames[i].Name);
79  }
80  }
81 
82  // Check there are no repeat column names in the table.
83  for (int i = 0; i < sz; ++i) {
84  var columnName = newColumnNames[i];
85  for (int n = i + 1; n < sz; ++n) {
86  if (newColumnNames[n].Equals(columnName))
87  throw new InvalidOperationException(String.Format("Duplicate column name '{0}' in view. A view may not contain duplicate column names.", columnName));
88  }
89  }
90 
91  // Wrap the plan around a SubsetNode plan
92  queryPlan = new SubsetNode(queryPlan, originalNames, newColumnNames);
93 
94  return new Prepared(viewName, QueryExpression, queryPlan, ReplaceIfExists);
95  }
96 
97  #region Prepared
98 
99  [Serializable]
101  internal Prepared(ObjectName viewName, SqlQueryExpression queryExpression, IQueryPlanNode queryPlan, bool replaceIfExists) {
102  ViewName = viewName;
103  QueryPlan = queryPlan;
104  ReplaceIfExists = replaceIfExists;
105  QueryExpression = queryExpression;
106  }
107 
108  private Prepared(ObjectData data) {
109  ViewName = data.GetValue<ObjectName>("Name");
110  QueryPlan = data.GetValue<IQueryPlanNode>("QueryPlan");
111  ReplaceIfExists = data.GetBoolean("ReplaceIfExists");
112  QueryExpression = data.GetValue<SqlQueryExpression>("QueryExpression");
113  }
114 
115  public ObjectName ViewName { get; private set; }
116 
117  public IQueryPlanNode QueryPlan { get; private set; }
118 
119  public bool ReplaceIfExists { get; set; }
120 
121  public SqlQueryExpression QueryExpression { get; private set; }
122 
123  protected override void GetData(SerializeData data) {
124  data.SetValue("Name", ViewName);
125  data.SetValue("QueryPlan", QueryPlan);
126  data.SetValue("QueryExpression", QueryExpression);
127  data.SetValue("ReplaceIfExists", ReplaceIfExists);
128  }
129 
130  protected override void ExecuteStatement(ExecutionContext context) {
131  // We have to execute the plan to get the TableInfo that represents the
132  // result of the view execution.
133  var table = QueryPlan.Evaluate(context.Request);
134  var tableInfo = table.TableInfo.Alias(ViewName);
135 
136  var viewInfo = new ViewInfo(tableInfo, QueryExpression, QueryPlan);
137  context.Request.Query.DefineView(viewInfo, ReplaceIfExists);
138  }
139  }
140 
141  #endregion
142 
143  #region PreparedSerializer
144 
145  //internal class PreparedSerializer : ObjectBinarySerializer<Prepared> {
146  // public override void Serialize(Prepared obj, BinaryWriter writer) {
147  // ObjectName.Serialize(obj.ViewName, writer);
148 
149  // var queryPlanTypeName = obj.QueryPlan.GetType().FullName;
150  // writer.Write(queryPlanTypeName);
151 
152  // QueryPlanSerializers.Serialize(obj.QueryPlan, writer);
153  // SqlExpression.Serialize(obj.QueryExpression, writer);
154  // writer.Write(obj.ReplaceIfExists);
155  // }
156 
157  // public override Prepared Deserialize(BinaryReader reader) {
158  // var viewName = ObjectName.Deserialize(reader);
159 
160  // var queryPlanTypeName = reader.ReadString();
161  // var queryPlanType = Type.GetType(queryPlanTypeName, true);
162  // var queryPlan = QueryPlanSerializers.Deserialize(queryPlanType, reader);
163 
164  // var queryExpression = SqlExpression.Deserialize(reader) as SqlQueryExpression;
165  // var replaceIfExists = reader.ReadBoolean();
166 
167  // return new Prepared(viewName, queryExpression, queryPlan, replaceIfExists);
168  // }
169  //}
170 
171  #endregion
172  }
173 }
Prepared(ObjectName viewName, SqlQueryExpression queryExpression, IQueryPlanNode queryPlan, bool replaceIfExists)
override void ExecuteStatement(ExecutionContext context)
void SetValue(string key, Type type, object value)
Describes the name of an object within a database.
Definition: ObjectName.cs:44
CreateViewStatement(string viewName, SqlQueryExpression queryExpression)
A node element of a query plan tree. /summary>
Represents the foundation class of SQL statements to be executed.
Definition: SqlStatement.cs:32
static QueryExpressionFrom Create(IRequest context, SqlQueryExpression expression)
new IQueryContext Context
Definition: IQuery.cs:21
CreateViewStatement(string viewName, IEnumerable< string > columnNames, SqlQueryExpression queryExpression)