1 /*
2  * Copyright 2015-2018 HuntLabs.cn
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 module hunt.sql.repository.Schema;
17 
18 import hunt.sql.SQLUtils;
19 import hunt.sql.ast.SQLDataType;
20 import hunt.sql.ast.SQLExpr;
21 import hunt.sql.ast.SQLName;
22 import hunt.sql.ast.SQLStatement;
23 import hunt.sql.ast.expr.SQLAggregateExpr;
24 import hunt.sql.ast.expr.SQLAllColumnExpr;
25 import hunt.sql.ast.expr.SQLIdentifierExpr;
26 import hunt.sql.ast.expr.SQLPropertyExpr;
27 import hunt.sql.ast.statement;
28 import hunt.sql.dialect.mysql.ast.statement.MySqlCreateTableStatement;
29 import hunt.sql.dialect.mysql.visitor.MySqlASTVisitorAdapter;
30 // import hunt.sql.dialect.oracle.ast.stmt.OracleCreateTableStatement;
31 // import hunt.sql.dialect.oracle.visitor.OracleASTVisitorAdapter;
32 import hunt.sql.visitor.SQLASTVisitor;
33 import hunt.sql.util.FnvHash;
34 import hunt.sql.util.DBType;
35 import hunt.sql.repository.SchemaObjectType;
36 
37 import hunt.collection;
38 import hunt.Long;
39 import hunt.String;
40 import hunt.sql.repository.SchemaObject;
41 import std.uni;
42 import hunt.sql.repository.SchemaRepository;
43 import hunt.text;
44 /**
45  * Created by wenshao on 21/07/2017.
46  */
47 public class Schema {
48     private string name;
49 
50     public  Map!(Long, SchemaObject) objects;
51 
52     public  Map!(Long, SchemaObject) _functions;
53 
54     private SchemaRepository repository;
55 
56     this()
57     {
58         objects = new HashMap!(Long, SchemaObject)();
59         _functions  = new HashMap!(Long, SchemaObject)();
60     }
61 
62     public this(SchemaRepository repository) {
63         this(repository, null);
64     }
65 
66     public this(SchemaRepository repository, string name) {
67         this();
68         this.repository = repository;
69         this.name = name;
70     }
71 
72     public string getName() {
73         return name;
74     }
75 
76     public void setName(string name) {
77         this.name = name;
78     }
79 
80 
81     public SchemaObject findTable(string tableName) {
82         long hashCode64 = FnvHash.hashCode64(tableName);
83         return findTable(hashCode64);
84     }
85 
86     public SchemaObject findTable(long nameHashCode64) {
87         SchemaObject object = objects.get(new Long(nameHashCode64));
88 
89         if (object !is null && object.getType() == SchemaObjectType.Table) {
90             return object;
91         }
92 
93         return null;
94     }
95 
96     public SchemaObject findTableOrView(string tableName) {
97         long hashCode64 = FnvHash.hashCode64(tableName);
98         return findTableOrView(hashCode64);
99     }
100 
101     public SchemaObject findTableOrView(long hashCode64) {
102         SchemaObject object = objects.get(new Long(hashCode64));
103 
104         if (object is null) {
105             return null;
106         }
107 
108         SchemaObjectType type = object.getType();
109         if (type == SchemaObjectType.Table || type == SchemaObjectType.View) {
110             return object;
111         }
112 
113         return null;
114     }
115 
116     public SchemaObject findFunction(string _functionName) {
117         _functionName = SQLUtils.normalize(_functionName);
118         string lowerName = toLower(_functionName);
119         return _functions.get(new Long(lowerName));
120     }
121 
122     public bool isSequence(string name) {
123         long nameHashCode64 = FnvHash.hashCode64(name);
124         SchemaObject object = objects.get(new Long(nameHashCode64));
125         return object !is null
126                 && object.getType() == SchemaObjectType.Sequence;
127     }
128 
129 
130     public SchemaObject findTable(SQLTableSource tableSource, string _alias) {
131         if (cast(SQLExprTableSource)(tableSource) !is null) {
132             if (equalsIgnoreCase(_alias, tableSource.computeAlias())) {
133                 SQLExprTableSource exprTableSource = cast(SQLExprTableSource) tableSource;
134 
135                 SchemaObject tableObject = exprTableSource.getSchemaObject();
136                 if (tableObject !is  null) {
137                     return tableObject;
138                 }
139 
140                 SQLExpr expr = exprTableSource.getExpr();
141                 if (cast(SQLIdentifierExpr)(expr) !is null) {
142                     long tableNameHashCode64 = (cast(SQLIdentifierExpr) expr).nameHashCode64();
143 
144                     tableObject = findTable(tableNameHashCode64);
145                     if (tableObject !is null) {
146                         exprTableSource.setSchemaObject(tableObject);
147                     }
148                     return tableObject;
149                 }
150 
151                 if (cast(SQLPropertyExpr)(expr) !is null) {
152                     long tableNameHashCode64 = (cast(SQLPropertyExpr) expr).nameHashCode64();
153 
154                     tableObject = findTable(tableNameHashCode64);
155                     if (tableObject !is null) {
156                         exprTableSource.setSchemaObject(tableObject);
157                     }
158                     return tableObject;
159                 }
160             }
161             return null;
162         }
163 
164         if (cast(SQLJoinTableSource)(tableSource) !is null) {
165             SQLJoinTableSource join = cast(SQLJoinTableSource) tableSource;
166             SQLTableSource left = join.getLeft();
167 
168             SchemaObject tableObject = findTable(left, _alias);
169             if (tableObject !is null) {
170                 return tableObject;
171             }
172 
173             SQLTableSource right = join.getRight();
174             tableObject = findTable(right, _alias);
175             return tableObject;
176         }
177 
178         return null;
179     }
180 
181     public SQLColumnDefinition findColumn(SQLTableSource tableSource, SQLSelectItem selectItem) {
182         if (selectItem is null) {
183             return null;
184         }
185 
186         return findColumn(tableSource, selectItem.getExpr());
187     }
188 
189     public SQLColumnDefinition findColumn(SQLTableSource tableSource, SQLExpr expr) {
190         SchemaObject object = findTable(tableSource, expr);
191         if (object !is null) {
192             if (cast(SQLAggregateExpr)(expr) !is null) {
193                 SQLAggregateExpr aggregateExpr = cast(SQLAggregateExpr) expr;
194                 string _function = aggregateExpr.getMethodName();
195                 if ("min".equalsIgnoreCase(_function)
196                         || "max".equalsIgnoreCase(_function)) {
197                     SQLExpr arg = aggregateExpr.getArguments().get(0);
198                     expr = arg;
199                 }
200             }
201 
202             if (cast(SQLName)(expr) !is null) {
203                 return object.findColumn((cast(SQLName) expr).getSimpleName());
204             }
205         }
206 
207         return null;
208     }
209 
210     public SchemaObject findTable(SQLTableSource tableSource, SQLSelectItem selectItem) {
211         if (selectItem is null) {
212             return null;
213         }
214 
215         return findTable(tableSource, selectItem.getExpr());
216     }
217 
218     public SchemaObject findTable(SQLTableSource tableSource, SQLExpr expr) {
219         if (cast(SQLAggregateExpr)(expr) !is null) {
220             SQLAggregateExpr aggregateExpr = cast(SQLAggregateExpr) expr;
221             string _function = aggregateExpr.getMethodName();
222             if ("min".equalsIgnoreCase(_function)
223                     || "max".equalsIgnoreCase(_function)) {
224                 SQLExpr arg = aggregateExpr.getArguments().get(0);
225                 return findTable(tableSource, arg);
226             }
227         }
228 
229         if (cast(SQLPropertyExpr)(expr) !is null) {
230             string ownerName = (cast(SQLPropertyExpr) expr).getOwnernName();
231             return findTable(tableSource, ownerName);
232         }
233 
234         if (cast(SQLAllColumnExpr)(expr) !is null || cast(SQLIdentifierExpr)(expr) !is null) {
235             if (cast(SQLExprTableSource)(tableSource) !is null) {
236                 return findTable(tableSource, tableSource.computeAlias());
237             }
238 
239             if (cast(SQLJoinTableSource)(tableSource) !is null) {
240                 SQLJoinTableSource join = cast(SQLJoinTableSource) tableSource;
241 
242                 SchemaObject table = findTable(join.getLeft(), expr);
243                 if (table is null) {
244                     table = findTable(join.getRight(), expr);
245                 }
246                 return table;
247             }
248             return null;
249         }
250 
251         return null;
252     }
253 
254     public Map!(string, SchemaObject) getTables(SQLTableSource x) {
255         Map!(string, SchemaObject) tables = new LinkedHashMap!(string, SchemaObject)();
256         computeTables(x, tables);
257         return tables;
258     }
259 
260     protected void computeTables(SQLTableSource x, Map!(string, SchemaObject) tables) {
261         if (x is null) {
262             return;
263         }
264 
265         if (cast(SQLExprTableSource)(x) !is null) {
266             SQLExprTableSource exprTableSource = cast(SQLExprTableSource) x;
267 
268             SQLExpr expr = exprTableSource.getExpr();
269             if (cast(SQLIdentifierExpr)(expr) !is null) {
270                 long tableNameHashCode64 = (cast(SQLIdentifierExpr) expr).nameHashCode64();
271                 string tableName = (cast(SQLIdentifierExpr) expr).getName();
272 
273                 SchemaObject table = exprTableSource.getSchemaObject();
274                 if (table is null) {
275                     table = findTable(tableNameHashCode64);
276 
277                     if (table !is null) {
278                         exprTableSource.setSchemaObject(table);
279                     }
280                 }
281 
282                 if (table !is null) {
283                     tables.put(tableName, table);
284 
285                     string _alias = x.getAlias();
286                     if (_alias !is null && !equalsIgnoreCase(_alias, tableName)) {
287                         tables.put(_alias, table);
288                     }
289                 }
290             }
291 
292             return;
293         }
294 
295         if (cast(SQLJoinTableSource)(x) !is null) {
296             SQLJoinTableSource join = cast(SQLJoinTableSource) x;
297             computeTables(join.getLeft(), tables);
298             computeTables(join.getRight(), tables);
299         }
300     }
301 
302     public int getTableCount() {
303         int count = 0;
304         foreach(SchemaObject object ; this.objects.values()) {
305             if (object.getType() == SchemaObjectType.Table) {
306                 count++;
307             }
308         }
309         return count;
310     }
311 
312     public SchemaObject[] getObjects() {
313         return (this.objects.values());
314     }
315 
316     public int getViewCount() {
317         int count = 0;
318         foreach(SchemaObject object ; this.objects.values()) {
319             if (object.getType() == SchemaObjectType.View) {
320                 count++;
321             }
322         }
323         return count;
324     }
325 
326     public List!(string) showTables() {
327         List!(string) tables = new ArrayList!(string)(objects.size());
328         foreach(SchemaObject object ; objects.values()) {
329             if (object.getType() == SchemaObjectType.Table) {
330                 tables.add(object.getName());
331             }
332         }
333         //Collections.sort(tables); //@gxc
334         return tables;
335     }
336 }