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.ast.statement.SQLExprTableSource;
17 
18 
19 import hunt.collection;
20 
21 import hunt.sql.SQLUtils;
22 import hunt.sql.ast.SQLExpr;
23 import hunt.sql.ast.SQLName;
24 import hunt.sql.ast.SQLReplaceable;
25 import hunt.sql.ast.SQLStatement;
26 import hunt.sql.ast.expr.SQLIdentifierExpr;
27 import hunt.sql.ast.expr.SQLPropertyExpr;
28 import hunt.sql.repository.SchemaObject;
29 import hunt.sql.visitor.SQLASTVisitor;
30 import hunt.sql.util.FnvHash;
31 import hunt.sql.ast.statement.SQLColumnDefinition;
32 import hunt.sql.ast.statement.SQLTableSourceImpl;
33 import hunt.sql.ast.statement.SQLTableSource;
34 import hunt.sql.ast.statement.SQLCreateTableStatement;
35 import hunt.util.StringBuilder;
36 
37 
38 public class SQLExprTableSource : SQLTableSourceImpl , SQLReplaceable {
39 
40     public SQLExpr     expr;
41     private List!SQLName partitions;
42     private SchemaObject  schemaObject;
43 
44     public this(){
45 
46     }
47 
48     public this(SQLExpr expr){
49         this(expr, null);
50     }
51 
52     public this(SQLExpr expr, string alias_P){
53         this.setExpr(expr);
54         this.setAlias(alias_P);
55     }
56 
57     public SQLExpr getExpr() {
58         return this.expr;
59     }
60 
61     public void setExpr(SQLExpr expr) {
62         if (expr !is null) {
63             expr.setParent(this);
64         }
65         this.expr = expr;
66     }
67 
68     public void setExpr(string name) {
69         this.setExpr(new SQLIdentifierExpr(name));
70     }
71 
72     public SQLName getName() {
73         if (cast(SQLName)(expr) !is null ) {
74             return cast(SQLName) expr;
75         }
76         return null;
77     }
78 
79     public string getSchema() {
80         if (expr is null) {
81             return null;
82         }
83 
84         if (cast(SQLPropertyExpr)(expr) !is null ) {
85             return (cast(SQLPropertyExpr) expr).getOwnernName();
86         }
87 
88         return null;
89     }
90 
91     public void setSchema(string schema) {
92         if (cast(SQLIdentifierExpr)(expr) !is null ) {
93             if (schema is null) {
94                 return;
95             }
96 
97             string ident = (cast(SQLIdentifierExpr) expr).getName();
98             this.setExpr(new SQLPropertyExpr(schema, ident));
99         } else if (cast(SQLPropertyExpr)(expr) !is null ) {
100             SQLPropertyExpr propertyExpr = cast(SQLPropertyExpr) expr;
101             if (schema is null) {
102                 setExpr(new SQLIdentifierExpr(propertyExpr.getName()));
103             } else {
104                 propertyExpr.setOwner(schema);
105             }
106         }
107     }
108 
109     public List!SQLName getPartitions() {
110         if (this.partitions is null) {
111             this.partitions = new ArrayList!SQLName(2);
112         }
113         
114         return partitions;
115     }
116     
117     public int getPartitionSize() {
118         if (this.partitions is null) {
119             return 0;
120         }
121         return this.partitions.size();
122     }
123 
124     public void addPartition(SQLName partition) {
125         if (partition !is null) {
126             partition.setParent(this);
127         }
128         
129         if (this.partitions is null) {
130             this.partitions = new ArrayList!SQLName(2);
131         }
132         this.partitions.add(partition);
133     }
134 
135     
136     override  protected void accept0(SQLASTVisitor visitor) {
137         if (visitor.visit(this)) {
138             acceptChild(visitor, this.expr);
139         }
140         visitor.endVisit(this);
141     }
142 
143     override public void output(StringBuilder buf) {
144         this.expr.output(buf);
145     }
146 
147     override
148     public bool opEquals(Object o) {
149         if (this == o) return true;
150         if (o is null || typeid(this) != typeid(o)) return false;
151 
152         SQLExprTableSource that = cast(SQLExprTableSource) o;
153 
154         if (expr !is null ? !(cast(Object)(expr)).opEquals(cast(Object)(that.expr)) : that.expr !is null) return false;
155         return partitions !is null ? (cast(Object)(partitions)).opEquals(cast(Object)(that.partitions)) : that.partitions is null;
156     }
157 
158     override
159     public size_t toHash() @trusted nothrow {
160         size_t result = expr !is null ? (cast(Object)expr).toHash() : 0;
161         result = 31 * result + (partitions !is null ? (cast(Object)partitions).toHash() : 0);
162         return result;
163     }
164 
165     override public string computeAlias() {
166         string alias_p = this.getAlias();
167 
168         if (alias_p is null) {
169             if (cast(SQLName)(expr) !is null ) {
170                 alias_p =(cast(SQLName) expr).getSimpleName();
171             }
172         }
173 
174         return SQLUtils.normalize(alias_p);
175     }
176 
177     override public SQLExprTableSource clone() {
178         SQLExprTableSource x = new SQLExprTableSource();
179         cloneTo(x);
180         return x;
181     }
182 
183     public void cloneTo(SQLExprTableSource x) {
184         x._alias = _alias;
185 
186         if (expr !is null) {
187             x.expr = expr.clone();
188         }
189 
190         if (partitions !is null) {
191             foreach (SQLName p ; partitions) {
192                 SQLName p1 = p.clone();
193                 x.addPartition(p1);
194             }
195         }
196     }
197 
198     public SchemaObject getSchemaObject() {
199         return schemaObject;
200     }
201 
202     public void setSchemaObject(SchemaObject schemaObject) {
203         this.schemaObject = schemaObject;
204     }
205 
206     override public bool containsAlias(string alias_p) {
207         long hashCode64 = FnvHash.hashCode64(alias_p);
208 
209         return containsAlias(hashCode64);
210     }
211 
212     public bool containsAlias(long aliasHash) {
213         if (this.aliasHashCode64() == aliasHash) {
214             return true;
215         }
216 
217         if (cast(SQLPropertyExpr)(expr) !is null ) {
218             long exprNameHash = (cast(SQLPropertyExpr) expr).hashCode64();
219             if (exprNameHash == aliasHash) {
220                 return true;
221             }
222         }
223 
224         if (cast(SQLName)(expr) !is null ) {
225             long exprNameHash = (cast(SQLName) expr).nameHashCode64();
226             return exprNameHash == aliasHash;
227         }
228 
229         return false;
230     }
231 
232     override public SQLColumnDefinition findColumn(string columnName) {
233         if (columnName is null) {
234             return null;
235         }
236 
237         long hash = FnvHash.hashCode64(columnName);
238         return findColumn(hash);
239     }
240 
241     override public SQLColumnDefinition findColumn(long columnNameHash) {
242         if (schemaObject is null) {
243             return null;
244         }
245 
246         SQLStatement stmt = schemaObject.getStatement();
247         if (cast(SQLCreateTableStatement)(stmt) !is null ) {
248             SQLCreateTableStatement createTableStmt = cast(SQLCreateTableStatement) stmt;
249             return createTableStmt.findColumn(columnNameHash);
250         }
251         return null;
252     }
253 
254     override public SQLTableSource findTableSourceWithColumn(string columnName) {
255         if (columnName is null) {
256             return null;
257         }
258 
259         long hash = FnvHash.hashCode64(columnName);
260         return findTableSourceWithColumn(hash);
261     }
262 
263     override public SQLTableSource findTableSourceWithColumn(long columnName_hash) {
264         if (schemaObject !is null) {
265             SQLStatement stmt = schemaObject.getStatement();
266             if (cast(SQLCreateTableStatement)(stmt) !is null ) {
267                 SQLCreateTableStatement createTableStmt = cast(SQLCreateTableStatement) stmt;
268                 if (createTableStmt.findColumn(columnName_hash) !is null) {
269                     return this;
270                 }
271             }
272         }
273 
274         if (cast(SQLIdentifierExpr)(expr) !is null ) {
275             SQLTableSource tableSource = (cast(SQLIdentifierExpr) expr).getResolvedTableSource();
276             if (tableSource !is null) {
277                 return tableSource.findTableSourceWithColumn(columnName_hash);
278             }
279         }
280 
281         return null;
282     }
283 
284     override public SQLTableSource findTableSource(long alias_hash) {
285         if (alias_hash == 0) {
286             return null;
287         }
288 
289         if (aliasHashCode64() == alias_hash) {
290             return this;
291         }
292 
293         if (cast(SQLName)(expr) !is null ) {
294             long exprNameHash = (cast(SQLName) expr).nameHashCode64();
295             if (exprNameHash == alias_hash) {
296                 return this;
297             }
298         }
299 
300         if (cast(SQLPropertyExpr)(expr) !is null ) {
301             long hash = (cast(SQLPropertyExpr) expr).hashCode64();
302             if (hash == alias_hash) {
303                 return this;
304             }
305         }
306 
307         return null;
308     }
309 
310     override
311     public bool replace(SQLExpr expr, SQLExpr target) {
312         if (expr == this.expr) {
313             this.setExpr(target);
314             return true;
315         }
316         return false;
317     }
318 }