|
| 1 | + |
1 | 2 | using System.Collections.Generic;
|
2 |
| -using MiniSQL.Library.Models; |
| 3 | +using System.IO; |
| 4 | +using MiniSQL.BufferManager.Controllers; |
3 | 5 | using MiniSQL.Library.Interfaces;
|
4 |
| -using System; |
5 |
| -using System.Linq; |
| 6 | +using MiniSQL.Library.Models; |
6 | 7 |
|
7 | 8 | namespace MiniSQL.Api.Controllers
|
8 | 9 | {
|
9 | 10 | public class ApiController : IApi
|
10 | 11 | {
|
| 12 | + private readonly DatabaseBuilder _builder; |
11 | 13 |
|
12 |
| - private readonly IInterpreter _interpreter; |
13 |
| - private readonly ICatalogManager _catalogManager; |
14 |
| - private readonly IRecordManager _recordManager; |
15 |
| - |
16 |
| - public ApiController(IInterpreter interpreter, ICatalogManager catalogManager, IRecordManager recordManager) |
17 |
| - { |
18 |
| - _catalogManager = catalogManager; |
19 |
| - _interpreter = interpreter; |
20 |
| - _recordManager = recordManager; |
21 |
| - } |
| 14 | + private IDatabaseController _database; |
| 15 | + private Pager _pager; |
22 | 16 |
|
23 |
| - public List<SelectResult> Query(string sql) |
24 |
| - { |
25 |
| - List<SelectResult> selectResults = new List<SelectResult>(); |
26 |
| - Query query; |
27 |
| - try |
28 |
| - { |
29 |
| - query = Parse(sql); |
30 |
| - } |
31 |
| - catch (Exception ex) |
32 |
| - { |
33 |
| - throw new StatementPreCheckException(ex.Message, ex.InnerException); |
34 |
| - } |
35 |
| - foreach (IStatement statement in query.StatementList) |
36 |
| - { |
37 |
| - SelectResult selectResult = HandleStatement(statement); |
38 |
| - if (selectResult != null) |
39 |
| - { |
40 |
| - selectResults.Add(selectResult); |
41 |
| - } |
42 |
| - } |
43 |
| - return selectResults; |
44 |
| - } |
| 17 | + public bool IsUsingDatabase { get; private set; } = false; |
| 18 | + private string _nameOfDatabaseInUse; |
45 | 19 |
|
46 |
| - private SelectResult HandleStatement(IStatement statement) |
| 20 | + public ApiController(DatabaseBuilder builder) |
47 | 21 | {
|
48 |
| - SelectResult selectResult = null; |
49 |
| - switch (statement.Type) |
50 |
| - { |
51 |
| - case StatementType.CreateStatement: |
52 |
| - HandleStatement((CreateStatement)statement); |
53 |
| - break; |
54 |
| - case StatementType.DropStatement: |
55 |
| - HandleStatement((DropStatement)statement); |
56 |
| - break; |
57 |
| - case StatementType.DeleteStatement: |
58 |
| - HandleStatement((DeleteStatement)statement); |
59 |
| - break; |
60 |
| - case StatementType.InsertStatement: |
61 |
| - HandleStatement((InsertStatement)statement); |
62 |
| - break; |
63 |
| - case StatementType.SelectStatement: |
64 |
| - selectResult = HandleSelectStatement((SelectStatement)statement); |
65 |
| - break; |
66 |
| - case StatementType.ShowStatement: |
67 |
| - selectResult = HandleSelectStatement((ShowStatement)statement); |
68 |
| - break; |
69 |
| - case StatementType.ExecFileStatement: |
70 |
| - throw new Exception("Impossible reach"); |
71 |
| - } |
72 |
| - return selectResult; |
73 |
| - } |
74 |
| - |
75 |
| - // create statement |
76 |
| - private void HandleStatement(CreateStatement statement) |
77 |
| - { |
78 |
| - _catalogManager.CheckValidation(statement); |
79 |
| - switch (statement.CreateType) |
80 |
| - { |
81 |
| - case CreateType.Table: |
82 |
| - int newTableRoot = _recordManager.CreateTable(); |
83 |
| - _catalogManager.CreateStatement(statement, newTableRoot); |
84 |
| - break; |
85 |
| - case CreateType.Index: |
86 |
| - SchemaRecord tableSchema = _catalogManager.GetTableSchemaRecord(statement.TableName); |
87 |
| - int newIndexRoot = _recordManager.CreateIndex(tableSchema.RootPage, statement.AttributeName, tableSchema.SQL.AttributeDeclarations); |
88 |
| - _catalogManager.CreateStatement(statement, newIndexRoot); |
89 |
| - break; |
90 |
| - } |
| 22 | + _builder = builder; |
91 | 23 | }
|
92 | 24 |
|
93 |
| - // drop statement |
94 |
| - private void HandleStatement(DropStatement statement) |
| 25 | + // use database |
| 26 | + public void ChangeContext(string newDatabaseName) |
95 | 27 | {
|
96 |
| - _catalogManager.CheckValidation(statement); |
97 |
| - SchemaRecord schema; |
98 |
| - switch (statement.TargetType) |
| 28 | + if (IsUsingDatabase) |
99 | 29 | {
|
100 |
| - case DropTarget.Table: |
101 |
| - schema = _catalogManager.GetTableSchemaRecord(statement.TableName); |
102 |
| - List<SchemaRecord> indices = _catalogManager.GetIndicesSchemaRecord(statement.TableName); |
103 |
| - // drop table |
104 |
| - _catalogManager.DropStatement(statement); |
105 |
| - _recordManager.DropTable(schema.RootPage); |
106 |
| - // drop index trees |
107 |
| - foreach (SchemaRecord index in indices) |
108 |
| - { |
109 |
| - _recordManager.DropTable(index.RootPage); |
110 |
| - } |
111 |
| - break; |
112 |
| - case DropTarget.Index: |
113 |
| - schema = _catalogManager.GetIndexSchemaRecord(statement.IndexName); |
114 |
| - _catalogManager.DropStatement(statement); |
115 |
| - _recordManager.DropTable(schema.RootPage); |
116 |
| - break; |
| 30 | + _pager.Close(); |
117 | 31 | }
|
| 32 | + // init |
| 33 | + this.IsUsingDatabase = true; |
| 34 | + this._nameOfDatabaseInUse = newDatabaseName; |
| 35 | + (_database, _pager) = _builder.UseDatabase(newDatabaseName); |
118 | 36 | }
|
119 | 37 |
|
120 |
| - // delete statement |
121 |
| - // NOTICE: relative index trees will NOT change accordingly |
122 |
| - private void HandleStatement(DeleteStatement statement) |
123 |
| - { |
124 |
| - // get table and indices |
125 |
| - _catalogManager.CheckValidation(statement); |
126 |
| - SchemaRecord tableSchema = _catalogManager.GetTableSchemaRecord(statement.TableName); |
127 |
| - List<SchemaRecord> indexSchemas = _catalogManager.GetIndicesSchemaRecord(statement.TableName); |
128 |
| - |
129 |
| - // TODO |
130 |
| - // delete index records from index trees |
131 |
| - // __problem__: |
132 |
| - // attribute names := (priKey, a, b, c) |
133 |
| - // condition := b < 3 and c > 5 |
134 |
| - // fun facts: b and c both have index trees |
135 |
| - // issue: to delete the records satisfying the condition above |
136 |
| - |
137 |
| - // delete record from table tree |
138 |
| - int newTableRootPage = _recordManager.DeleteRecords(statement.Condition, tableSchema.SQL.PrimaryKey, tableSchema.SQL.AttributeDeclarations, tableSchema.RootPage); |
139 |
| - _catalogManager.TryUpdateSchemaRecord(statement.TableName, newTableRootPage); |
140 |
| - } |
141 |
| - |
142 |
| - private SelectResult HandleSelectStatement(ShowStatement statement) |
| 38 | + // delete database file |
| 39 | + public void DropDatabase(string databaseName) |
143 | 40 | {
|
144 |
| - List<SchemaRecord> tableSchemas = _catalogManager.GetTablesSchemaRecord(); |
145 |
| - SelectResult result = new SelectResult(); |
146 |
| - result.ColumnDeclarations = new List<AttributeDeclaration>() { new AttributeDeclaration() {AttributeName = "Table", Type = AttributeTypes.Char, CharLimit = 80}}; |
147 |
| - result.Rows = new List<List<AtomValue>>(); |
148 |
| - foreach (SchemaRecord tableSchema in tableSchemas) |
| 41 | + if (_nameOfDatabaseInUse == databaseName) |
149 | 42 | {
|
150 |
| - List<AtomValue> row = new List<AtomValue>(); |
151 |
| - AtomValue col = new AtomValue(); |
152 |
| - col.Type = AttributeTypes.Char; |
153 |
| - col.CharLimit = 80; |
154 |
| - col.StringValue = tableSchema.Name; |
155 |
| - row.Add(col); |
156 |
| - result.Rows.Add(row); |
| 43 | + _pager.Close(); |
| 44 | + IsUsingDatabase = false; |
157 | 45 | }
|
158 |
| - return result; |
| 46 | + File.Delete($"{databaseName}.minidb"); |
| 47 | + File.Delete($"{databaseName}.indices.dbcatalog"); |
| 48 | + File.Delete($"{databaseName}.tables.dbcatalog"); |
159 | 49 | }
|
160 | 50 |
|
161 |
| - private SelectResult HandleSelectStatement(SelectStatement statement) |
| 51 | + public void ClosePager() |
162 | 52 | {
|
163 |
| - bool isIndexTreeAvailable = false; |
164 |
| - // get table and indices |
165 |
| - _catalogManager.CheckValidation(statement); |
166 |
| - SchemaRecord tableSchema = _catalogManager.GetTableSchemaRecord(statement.FromTable); |
167 |
| - List<SchemaRecord> indexSchemas = _catalogManager.GetIndicesSchemaRecord(statement.FromTable); |
168 |
| - |
169 |
| - // select from index tree if possible |
170 |
| - AtomValue primaryKey = null; |
171 |
| - if (statement.Condition != null) |
172 |
| - { |
173 |
| - foreach (SchemaRecord indexSchema in indexSchemas) |
174 |
| - { |
175 |
| - // if there has a condition `=` on indexed column |
176 |
| - if (statement.Condition.Ands.ContainsKey(indexSchema.SQL.AttributeName) |
177 |
| - && statement.Condition.Ands[indexSchema.SQL.AttributeName].Operator == Operator.Equal) |
178 |
| - { |
179 |
| - isIndexTreeAvailable = true; |
180 |
| - // find out the primary key |
181 |
| - List<AtomValue> wrappedPrimaryKey = _recordManager.SelectRecord(statement.Condition.Ands[indexSchema.SQL.AttributeName].RightOperand.ConcreteValue, indexSchema.RootPage); |
182 |
| - primaryKey = wrappedPrimaryKey?[0]; |
183 |
| - break; |
184 |
| - } |
185 |
| - } |
186 |
| - } |
187 |
| - SelectResult result = new SelectResult(); |
188 |
| - result.ColumnDeclarations = tableSchema.SQL.AttributeDeclarations; |
189 |
| - // index tree is not available |
190 |
| - if (!isIndexTreeAvailable) |
191 |
| - { |
192 |
| - // select records from table tree |
193 |
| - List<List<AtomValue>> rows = _recordManager.SelectRecords(statement, tableSchema.SQL.PrimaryKey, tableSchema.SQL.AttributeDeclarations, tableSchema.RootPage); |
194 |
| - result.Rows = rows; |
195 |
| - } |
196 |
| - // index tree is available |
197 |
| - else |
198 |
| - { |
199 |
| - // select one record from table tree |
200 |
| - List<List<AtomValue>> rows = new List<List<AtomValue>>(); |
201 |
| - if (!object.ReferenceEquals(primaryKey, null)) |
202 |
| - { |
203 |
| - List<AtomValue> recordFromTable = _recordManager.SelectRecord(primaryKey, tableSchema.RootPage); |
204 |
| - rows.Add(recordFromTable); |
205 |
| - result.Rows = rows; |
206 |
| - } |
207 |
| - else // the primary key is null. |
208 |
| - // if primaryKey is null, |
209 |
| - // it means that from the index tree it could not find the primary key. |
210 |
| - // in order words, there is not a row existing in the table tree satisfying the condition. |
211 |
| - // thus, no need to visit the table tree |
212 |
| - { |
213 |
| - // assign an empty list |
214 |
| - result.Rows = new List<List<AtomValue>>(); |
215 |
| - } |
216 |
| - } |
217 |
| - return result; |
| 53 | + _pager.Close(); |
218 | 54 | }
|
219 | 55 |
|
220 |
| - private void HandleStatement(InsertStatement statement) |
| 56 | + public void FlushPages() |
221 | 57 | {
|
222 |
| - _catalogManager.CheckValidation(statement); |
223 |
| - // get table schema |
224 |
| - SchemaRecord schema = _catalogManager.GetTableSchemaRecord(statement.TableName); |
225 |
| - // adjust inlined type in insert statement |
226 |
| - if (schema.SQL.AttributeDeclarations.Count != statement.Values.Count) |
227 |
| - { |
228 |
| - throw new Exception("number of columns between \"create table\" and \"insert statement\' do not match"); |
229 |
| - } |
230 |
| - int i; |
231 |
| - for (i = 0; i < statement.Values.Count; i++) |
232 |
| - { |
233 |
| - statement.Values[i].CharLimit = schema.SQL.AttributeDeclarations[i].CharLimit; |
234 |
| - } |
235 |
| - // find out primary key from insert values |
236 |
| - AtomValue primaryKey = |
237 |
| - statement.Values[schema.SQL.AttributeDeclarations.FindIndex(x => |
238 |
| - x.AttributeName == schema.SQL.PrimaryKey)]; |
239 |
| - // insert into index trees |
240 |
| - List<SchemaRecord> indexSchemas = _catalogManager.GetIndicesSchemaRecord(statement.TableName); |
241 |
| - foreach (SchemaRecord indexSchema in indexSchemas) |
242 |
| - { |
243 |
| - // find indexed value from insert values |
244 |
| - AtomValue indexedValue = |
245 |
| - statement.Values[schema.SQL.AttributeDeclarations.FindIndex(x => |
246 |
| - x.AttributeName == indexSchema.SQL.AttributeName)]; |
247 |
| - // wrap up indexed value and primary key |
248 |
| - List<AtomValue> indexPrimaryKeyPair = new List<AtomValue>() { indexedValue, primaryKey }; |
249 |
| - // insert into index trees |
250 |
| - int newIndexRoot = _recordManager.InsertRecord(indexPrimaryKeyPair, indexedValue, indexSchema.RootPage); |
251 |
| - _catalogManager.TryUpdateSchemaRecord(indexSchema.Name, newIndexRoot); |
252 |
| - } |
253 |
| - // insert into table tree |
254 |
| - int newRoot = _recordManager.InsertRecord(statement.Values, primaryKey, schema.RootPage); |
255 |
| - _catalogManager.TryUpdateSchemaRecord(statement.TableName, newRoot); |
| 58 | + _pager.CleanAllPagesFromMainMemory(); |
256 | 59 | }
|
257 | 60 |
|
258 |
| - private Query Parse(string sql) |
| 61 | + public List<SelectResult> Query(string input) |
259 | 62 | {
|
260 |
| - return _interpreter.GetQuery(sql); |
| 63 | + List<SelectResult> selectResults = _database.Query(input.ToString()); |
| 64 | + return selectResults; |
261 | 65 | }
|
262 | 66 | }
|
263 | 67 | }
|
0 commit comments