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.SQLColumnDefinition;
17 
18 import hunt.collection;
19 
20 import hunt.sql.SQLUtils;
21 import hunt.sql.ast;
22 import hunt.sql.ast.expr.SQLCharExpr;
23 import hunt.sql.ast.expr.SQLIdentifierExpr;
24 import hunt.sql.ast.expr.SQLPropertyExpr;
25 import hunt.sql.visitor.SQLASTVisitor;
26 import hunt.sql.util.DBType;
27 import hunt.sql.ast.statement.SQLTableElement;
28 import hunt.sql.ast.statement.SQLColumnConstraint;
29 import hunt.Boolean;
30 import hunt.Integer;
31 
32 import hunt.sql.ast.statement.SQLNotNullConstraint;
33 import hunt.sql.ast.statement.SQLColumnPrimaryKey;
34 import hunt.sql.ast.statement.SQLCreateTableStatement;
35 import hunt.util.StringBuilder;
36 
37 public class SQLColumnDefinition : SQLObjectImpl , SQLTableElement, SQLObjectWithDataType, SQLReplaceable {
38     protected string                          dbType;
39 
40     protected SQLName                         name;
41     protected SQLDataType                     dataType;
42     protected SQLExpr                         defaultExpr;
43     protected  List!SQLColumnConstraint constraints;
44     protected SQLExpr                         comment;
45 
46     protected Boolean                         enable;
47     protected Boolean                         validate;
48     protected Boolean                         rely;
49 
50     // for mysql
51     protected bool                         autoIncrement = false;
52     protected SQLExpr                         onUpdate;
53     protected SQLExpr                         storage;
54     protected SQLExpr                         charsetExpr;
55     protected SQLExpr                         asExpr;
56     protected bool                         sorted        = false;
57     protected bool                         virtual       = false;
58 
59     protected Identity                        identity;
60     protected SQLExpr                         generatedAlawsAs;
61 
62     public this(){
63         constraints   = new ArrayList!SQLColumnConstraint(0);
64     }
65 
66     public Identity getIdentity() {
67         return identity;
68     }
69 
70     // for sqlserver
71     public void setIdentity(Identity x) {
72         if (x !is null) {
73             x.setParent(this);
74         }
75         this.identity = x;
76     }
77 
78     public SQLExpr getGeneratedAlawsAs() {
79         return generatedAlawsAs;
80     }
81 
82     public void setGeneratedAlawsAs(SQLExpr x) {
83         if (x !is null) {
84             x.setParent(this);
85         }
86         this.generatedAlawsAs = x;
87     }
88 
89     public Boolean getEnable() {
90         return enable;
91     }
92 
93     public void setEnable(Boolean enable) {
94         this.enable = enable;
95     }
96 
97     public Boolean getValidate() {
98         return validate;
99     }
100 
101     public void setValidate(Boolean validate) {
102         this.validate = validate;
103     }
104 
105     public Boolean getRely() {
106         return rely;
107     }
108 
109     public void setRely(Boolean rely) {
110         this.rely = rely;
111     }
112 
113     public SQLName getName() {
114         return name;
115     }
116 
117     public long nameHashCode64() {
118         if (name is null) {
119             return 0;
120         }
121 
122         return name.hashCode64();
123     }
124 
125     public string getNameAsString() {
126         if (name is null) {
127             return null;
128         }
129 
130         return (cast(Object)(name)).toString();
131     }
132 
133     public void setName(SQLName name) {
134         this.name = name;
135     }
136 
137     public void setName(string name) {
138         this.setName(new SQLIdentifierExpr(name));
139     }
140 
141     public SQLDataType getDataType() {
142         return dataType;
143     }
144 
145     public void setDataType(SQLDataType dataType) {
146         if (dataType !is null) {
147             dataType.setParent(this);
148         }
149         this.dataType = dataType;
150     }
151 
152     public SQLExpr getDefaultExpr() {
153         return defaultExpr;
154     }
155 
156     public void setDefaultExpr(SQLExpr defaultExpr) {
157         if (defaultExpr !is null) {
158             defaultExpr.setParent(this);
159         }
160         this.defaultExpr = defaultExpr;
161     }
162 
163     public List!SQLColumnConstraint getConstraints() {
164         return constraints;
165     }
166     
167     public void addConstraint(SQLColumnConstraint constraint) {
168         if (constraint !is null) {
169             constraint.setParent(this);
170         }
171         this.constraints.add(constraint);
172     }
173 
174     override public void output(StringBuilder buf) {
175         name.output(buf);
176         buf.append(' ');
177         this.dataType.output(buf);
178         if (defaultExpr !is null) {
179             buf.append(" DEFAULT ");
180             this.defaultExpr.output(buf);
181         }
182     }
183 
184     
185     override  protected void accept0(SQLASTVisitor visitor) {
186         if (visitor.visit(this)) {
187             this.acceptChild(visitor, name);
188             this.acceptChild(visitor, dataType);
189             this.acceptChild(visitor, defaultExpr);
190             this.acceptChild!SQLColumnConstraint(visitor, constraints);
191         }
192         visitor.endVisit(this);
193     }
194 
195     public SQLExpr getComment() {
196         return comment;
197     }
198 
199     public void setComment(string comment) {
200         this.setComment(new SQLCharExpr(comment));
201     }
202 
203     public void setComment(SQLExpr comment) {
204         if (comment !is null) {
205             comment.setParent(this);
206         }
207         this.comment = comment;
208     }
209 
210     public bool isVirtual() {
211         return virtual;
212     }
213 
214     public void setVirtual(bool virtual) {
215         this.virtual = virtual;
216     }
217 
218     public bool isSorted() {
219         return sorted;
220     }
221 
222     public void setSorted(bool sorted) {
223         this.sorted = sorted;
224     }
225 
226     public SQLExpr getCharsetExpr() {
227         return charsetExpr;
228     }
229 
230     public void setCharsetExpr(SQLExpr charsetExpr) {
231         if (charsetExpr !is null) {
232             charsetExpr.setParent(this);
233         }
234         this.charsetExpr = charsetExpr;
235     }
236 
237     public SQLExpr getAsExpr() {
238         return asExpr;
239     }
240 
241     public void setAsExpr(SQLExpr asExpr) {
242         if (charsetExpr !is null) {
243             charsetExpr.setParent(this);
244         }
245         this.asExpr = asExpr;
246     }
247 
248     public bool isAutoIncrement() {
249         return autoIncrement;
250     }
251 
252     public void setAutoIncrement(bool autoIncrement) {
253         this.autoIncrement = autoIncrement;
254     }
255 
256     public SQLExpr getOnUpdate() {
257         return onUpdate;
258     }
259 
260     public void setOnUpdate(SQLExpr onUpdate) {
261         this.onUpdate = onUpdate;
262     }
263 
264     public SQLExpr getStorage() {
265         return storage;
266     }
267 
268     public void setStorage(SQLExpr storage) {
269         this.storage = storage;
270     }
271 
272     override
273     public bool replace(SQLExpr expr, SQLExpr target) {
274         if (defaultExpr == expr) {
275             setDefaultExpr(target);
276             return true;
277         }
278 
279         if (name == expr) {
280             setName(cast(SQLName) target);
281             return true;
282         }
283 
284         return false;
285     }
286 
287     public static class Identity : SQLObjectImpl {
288 
289         private Integer seed;
290         private Integer increment;
291 
292         private bool notForReplication;
293 
294         public this(){
295 
296         }
297 
298         public Integer getSeed() {
299             return seed;
300         }
301 
302         public void setSeed(Integer seed) {
303             this.seed = seed;
304         }
305 
306         public Integer getIncrement() {
307             return increment;
308         }
309 
310         public void setIncrement(Integer increment) {
311             this.increment = increment;
312         }
313 
314         public bool isNotForReplication() {
315             return notForReplication;
316         }
317 
318         public void setNotForReplication(bool notForReplication) {
319             this.notForReplication = notForReplication;
320         }
321 
322         override
323         public void accept0(SQLASTVisitor visitor) {
324             visitor.visit(this);
325             visitor.endVisit(this);
326         }
327 
328         override public Identity clone () {
329             Identity x = new Identity();
330             x.seed = seed;
331             x.increment = increment;
332             x.notForReplication = notForReplication;
333             return x;
334         }
335     }
336 
337     public string computeAlias() {
338         string alias_p = null;
339 
340         if (cast(SQLIdentifierExpr)(name) !is null) {
341             alias_p = (cast(SQLIdentifierExpr) name).getName();
342         } else if (cast(SQLPropertyExpr)(name) !is null ) {
343             alias_p = (cast(SQLPropertyExpr) name).getName();
344         }
345 
346         return SQLUtils.normalize(alias_p);
347     }
348 
349     override public SQLColumnDefinition clone() {
350         SQLColumnDefinition x = new SQLColumnDefinition();
351         x.setDbType(dbType);
352 
353         if(name !is null) {
354             x.setName(name.clone());
355         }
356 
357         if (dataType !is null) {
358             x.setDataType(dataType.clone());
359         }
360 
361         if (defaultExpr !is null) {
362             x.setDefaultExpr(defaultExpr.clone());
363         }
364 
365         foreach (SQLColumnConstraint item ; constraints) {
366             SQLColumnConstraint itemCloned = item.clone();
367             itemCloned.setParent(x);
368             x.constraints.add(itemCloned);
369         }
370 
371         if (comment !is null) {
372             x.setComment(comment.clone());
373         }
374 
375         x.enable = enable;
376         x.validate = validate;
377         x.rely = rely;
378 
379         x.autoIncrement = autoIncrement;
380 
381         if (onUpdate !is null) {
382             x.setOnUpdate(onUpdate.clone());
383         }
384 
385         if (storage !is null) {
386             x.setStorage(storage.clone());
387         }
388 
389         if (charsetExpr !is null) {
390             x.setCharsetExpr(charsetExpr.clone());
391         }
392 
393         if (asExpr !is null) {
394             x.setAsExpr(asExpr.clone());
395         }
396 
397         x.sorted = sorted;
398         x.virtual = virtual;
399 
400         if (identity !is null) {
401             x.setIdentity(identity.clone());
402         }
403 
404         return x;
405     }
406 
407     public string getDbType() {
408         return dbType;
409     }
410 
411     public void setDbType(string dbType) {
412         this.dbType = dbType;
413     }
414 
415     public void simplify() {
416         enable = Boolean.FALSE;
417         validate = Boolean.FALSE;
418         rely = Boolean.FALSE;
419 
420 
421         if (cast(SQLIdentifierExpr)(this.name) !is null ) {
422             SQLIdentifierExpr identExpr = cast(SQLIdentifierExpr) this.name;
423             string columnName = identExpr.getName();
424             string normalized = SQLUtils.normalize(columnName, dbType);
425             if (normalized != columnName) {
426                 this.setName(normalized);
427             }
428         }
429     }
430 
431     public bool containsNotNullConstaint() {
432         foreach (SQLColumnConstraint constraint ; this.constraints) {
433             if (cast(SQLNotNullConstraint)(constraint) !is null ) {
434                 return true;
435             }
436         }
437 
438         return false;
439     }
440 
441     public bool isPrimaryKey() {
442         foreach (SQLColumnConstraint constraint ; constraints) {
443             if (cast(SQLColumnPrimaryKey)(constraint) !is null ) {
444                 return true;
445             }
446         }
447 
448         if (cast(SQLCreateTableStatement)(parent) !is null ) {
449             return (cast(SQLCreateTableStatement) parent)
450                     .isPrimaryColumn(nameHashCode64());
451         }
452 
453         return false;
454     }
455 
456     override public string toString() {
457         return SQLUtils.toSQLString(this, dbType);
458     }
459 }