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.stat.TableStat;
17 
18 import hunt.sql.SQLUtils;
19 import hunt.sql.ast.SQLExpr;
20 import hunt.sql.ast.expr.SQLPropertyExpr;
21 import hunt.serialization.JsonSerializer;
22 import hunt.sql.util.FnvHash;
23 import hunt.sql.util.DBType;
24 import hunt.String;
25 import hunt.collection;
26 import hunt.String;
27 import std.string;
28 import hunt.text;
29 
30 public class TableStat
31 {
32 
33     int selectCount = 0;
34     int updateCount = 0;
35     int deleteCount = 0;
36     int insertCount = 0;
37     int dropCount = 0;
38     int mergeCount = 0;
39     int createCount = 0;
40     int alterCount = 0;
41     int createIndexCount = 0;
42     int dropIndexCount = 0;
43     int referencedCount = 0;
44 
45     public int getReferencedCount()
46     {
47         return referencedCount;
48     }
49 
50     public void incrementReferencedCount()
51     {
52         referencedCount++;
53     }
54 
55     public int getDropIndexCount()
56     {
57         return dropIndexCount;
58     }
59 
60     public void incrementDropIndexCount()
61     {
62         this.dropIndexCount++;
63     }
64 
65     public int getCreateIndexCount()
66     {
67         return createIndexCount;
68     }
69 
70     public void incrementCreateIndexCount()
71     {
72         createIndexCount++;
73     }
74 
75     public int getAlterCount()
76     {
77         return alterCount;
78     }
79 
80     public void incrementAlterCount()
81     {
82         this.alterCount++;
83     }
84 
85     public int getCreateCount()
86     {
87         return createCount;
88     }
89 
90     public void incrementCreateCount()
91     {
92         this.createCount++;
93     }
94 
95     public int getMergeCount()
96     {
97         return mergeCount;
98     }
99 
100     public void incrementMergeCount()
101     {
102         this.mergeCount++;
103     }
104 
105     public int getDropCount()
106     {
107         return dropCount;
108     }
109 
110     public void incrementDropCount()
111     {
112         dropCount++;
113     }
114 
115     public void setDropCount(int dropCount)
116     {
117         this.dropCount = dropCount;
118     }
119 
120     public int getSelectCount()
121     {
122         return selectCount;
123     }
124 
125     public void incrementSelectCount()
126     {
127         selectCount++;
128     }
129 
130     public void setSelectCount(int selectCount)
131     {
132         this.selectCount = selectCount;
133     }
134 
135     public int getUpdateCount()
136     {
137         return updateCount;
138     }
139 
140     public void incrementUpdateCount()
141     {
142         updateCount++;
143     }
144 
145     public void setUpdateCount(int updateCount)
146     {
147         this.updateCount = updateCount;
148     }
149 
150     public int getDeleteCount()
151     {
152         return deleteCount;
153     }
154 
155     public void incrementDeleteCount()
156     {
157         this.deleteCount++;
158     }
159 
160     public void setDeleteCount(int deleteCount)
161     {
162         this.deleteCount = deleteCount;
163     }
164 
165     public void incrementInsertCount()
166     {
167         this.insertCount++;
168     }
169 
170     public int getInsertCount()
171     {
172         return insertCount;
173     }
174 
175     public void setInsertCount(int insertCount)
176     {
177         this.insertCount = insertCount;
178     }
179 
180     override public string toString()
181     {
182         StringBuilder buf = new StringBuilder(4);
183         if (mergeCount > 0)
184         {
185             buf.append("Merge");
186         }
187         if (insertCount > 0)
188         {
189             buf.append("Insert");
190         }
191         if (updateCount > 0)
192         {
193             buf.append("Update");
194         }
195         if (selectCount > 0)
196         {
197             buf.append("Select");
198         }
199         if (deleteCount > 0)
200         {
201             buf.append("Delete");
202         }
203         if (dropCount > 0)
204         {
205             buf.append("Drop");
206         }
207         if (createCount > 0)
208         {
209             buf.append("Create");
210         }
211         if (alterCount > 0)
212         {
213             buf.append("Alter");
214         }
215         if (createIndexCount > 0)
216         {
217             buf.append("CreateIndex");
218         }
219         if (dropIndexCount > 0)
220         {
221             buf.append("DropIndex");
222         }
223 
224         return buf.toString();
225     }
226 
227     public static class Name
228     {
229         private  string name;
230         private  long _hashCode64;
231 
232         public this(string name)
233         {
234             this(name, FnvHash.hashCode64(name));
235         }
236 
237         public this(string name, long _hashCode64)
238         {
239             this.name = name;
240             this._hashCode64 = _hashCode64;
241         }
242 
243         public string getName()
244         {
245             return this.name;
246         }
247 
248         override public size_t toHash() @trusted nothrow
249         {
250             try{
251                 long value = hashCode64();
252                 return cast(size_t)(value ^ (value >>> 32));
253             }
254             catch(Exception e){}
255             return 0;
256         }
257 
258         public long hashCode64()
259         {
260             return _hashCode64;
261         }
262 
263         override public bool opEquals(Object o)
264         {
265             if (!(cast(Name)(o) !is null))
266             {
267                 return false;
268             }
269 
270             Name other = cast(Name) o;
271             return this._hashCode64 == other._hashCode64;
272         }
273 
274         override public string toString()
275         {
276             return SQLUtils.normalize(this.name);
277         }
278     }
279 
280     public static class Relationship
281     {
282         private Column left;
283         private Column right;
284         private string operator;
285 
286         public this(Column left, Column right, string operator)
287         {
288             this.left = left;
289             this.right = right;
290             this.operator = operator;
291         }
292 
293         public Column getLeft()
294         {
295             return left;
296         }
297 
298         public Column getRight()
299         {
300             return right;
301         }
302 
303         public string getOperator()
304         {
305             return operator;
306         }
307 
308         override public size_t toHash() @trusted nothrow
309         {
310              int prime = 31;
311             size_t result = 1;
312             result = prime * result + ((left is null) ? 0 : (cast(Object)left).toHash());
313             result = prime * result + ((operator is null) ? 0 : hashOf(operator));
314             result = prime * result + ((right is null) ? 0 : (cast(Object)right).toHash());
315             return result;
316         }
317 
318         override public bool opEquals(Object obj)
319         {
320             if (this == obj)
321             {
322                 return true;
323             }
324             if (obj is null)
325             {
326                 return false;
327             }
328             if (typeid(this) != typeid(obj))
329             {
330                 return false;
331             }
332             Relationship other = cast(Relationship) obj;
333             if (left is null)
334             {
335                 if (other.left !is null)
336                 {
337                     return false;
338                 }
339             }
340             else if (!(cast(Object)(left)).opEquals(cast(Object)(other.left)))
341             {
342                 return false;
343             }
344             if (operator is null)
345             {
346                 if (other.operator !is null)
347                 {
348                     return false;
349                 }
350             }
351             else if (!(operator == other.operator))
352             {
353                 return false;
354             }
355             if (right is null)
356             {
357                 if (other.right !is null)
358                 {
359                     return false;
360                 }
361             }
362             else if (!(cast(Object)(right)).opEquals(cast(Object)(other.right)))
363             {
364                 return false;
365             }
366             return true;
367         }
368 
369         override public string toString()
370         {
371             return left.toString ~ " " ~ operator ~ " " ~ right.toString;
372         }
373 
374     }
375 
376     public static class Condition
377     {
378 
379         private  Column column;
380         private  string operator;
381         private  List!(Object) values;
382 
383         this()
384         {
385             values = new ArrayList!(Object)();
386         }
387 
388         public this(Column column, string operator)
389         {
390             this();
391             this.column = column;
392             this.operator = operator;
393         }
394 
395         public Column getColumn()
396         {
397             return column;
398         }
399 
400         public string getOperator()
401         {
402             return operator;
403         }
404 
405         public List!(Object) getValues()
406         {
407             return values;
408         }
409 
410         public void addValue(Object value)
411         {
412             this.values.add(value);
413         }
414 
415         override public size_t toHash() @trusted nothrow
416         {
417              int prime = 31;
418             size_t result = 1;
419             result = prime * result + ((column is null) ? 0 : (cast(Object)column).toHash());
420             result = prime * result + ((operator is null) ? 0 : hashOf(operator));
421             return result;
422         }
423 
424         override public bool opEquals(Object obj)
425         {
426             if (this == obj)
427             {
428                 return true;
429             }
430             if (obj is null)
431             {
432                 return false;
433             }
434             if (typeid(this) != typeid(obj))
435             {
436                 return false;
437             }
438             Condition other = cast(Condition) obj;
439             if (column is null)
440             {
441                 if (other.column !is null)
442                 {
443                     return false;
444                 }
445             }
446             else if (!(cast(Object)(column)).opEquals(cast(Object)(other.column)))
447             {
448                 return false;
449             }
450             if (operator is null)
451             {
452                 if (other.operator !is null)
453                 {
454                     return false;
455                 }
456             }
457             else if (!(operator == other.operator))
458             {
459                 return false;
460             }
461             return true;
462         }
463 
464         override public string toString()
465         {
466             StringBuilder buf = new StringBuilder();
467             buf.append((cast(Object)(this.column)).toString());
468             buf.append(' ');
469             buf.append(this.operator);
470 
471             if (values.size() == 1)
472             {
473                 buf.append(' ');
474                 buf.append(String.valueOf(this.values.get(0)));
475             }
476             else if (values.size() > 0)
477             {
478                 buf.append(" (");
479                 for (int i = 0; i < values.size(); ++i)
480                 {
481                     if (i != 0)
482                     {
483                         buf.append(", ");
484                     }
485                     Object val = values.get(i);
486                     if (cast(String)(val) !is null)
487                     {
488                         string jsonStr = toJson(val).toString;
489                         buf.append(jsonStr);
490                     }
491                     else
492                     {
493                         buf.append(String.valueOf(val));
494                     }
495                 }
496                 buf.append(")");
497             }
498 
499             return buf.toString();
500         }
501     }
502 
503     public static class Column
504     {
505 
506         private  string table;
507         private  string name;
508         protected  long _hashCode64;
509 
510         private bool where;
511         private bool select;
512         private bool groupBy;
513         private bool having;
514         private bool join;
515 
516         private bool primaryKey; // for ddl
517         private bool unique; //
518 
519         private Map!(string, Object) attributes;
520 
521         private string fullName;
522 
523         /**
524          * @since 1.0.20
525          */
526         private string dataType;
527 
528         this()
529         {
530             attributes = new HashMap!(string, Object)();
531         }
532 
533         public this(string table, string name)
534         {
535             this();
536             this.table = table;
537             this.name = name;
538 
539             int p = cast(int)(table.indexOf('.'));
540             if (p !=  - 1)
541             {
542                 string dbType = null;
543                 if (table.indexOf('`') !=  - 1)
544                 {
545                     dbType = DBType.MYSQL.name;
546                 }
547                 else if (table.indexOf('[') !=  - 1)
548                 {
549                     dbType = DBType.SQL_SERVER.name;
550                 }
551                 else if (table.indexOf('@') !=  - 1)
552                 {
553                     dbType = DBType.ORACLE.name;
554                 }
555                 SQLExpr owner = SQLUtils.toSQLExpr(table, dbType);
556                 _hashCode64 = new SQLPropertyExpr(owner, name).hashCode64();
557             }
558             else
559             {
560                 _hashCode64 = FnvHash.hashCode64(table, name);
561             }
562         }
563 
564         public this(string table, string name, long _hashCode64)
565         {
566             this();
567             this.table = table;
568             this.name = name;
569             this._hashCode64 = _hashCode64;
570         }
571 
572         public string getTable()
573         {
574             return table;
575         }
576 
577         public string getFullName()
578         {
579             if (fullName is null)
580             {
581                 if (table is null)
582                 {
583                     fullName = name;
584                 }
585                 else
586                 {
587                     fullName = table ~ '.' ~ name;
588                 }
589             }
590 
591             return fullName;
592         }
593 
594         public long hashCode64()
595         {
596             return _hashCode64;
597         }
598 
599         public bool isWhere()
600         {
601             return where;
602         }
603 
604         public void setWhere(bool where)
605         {
606             this.where = where;
607         }
608 
609         public bool isSelect()
610         {
611             return select;
612         }
613 
614         public void setSelec(bool select)
615         {
616             this.select = select;
617         }
618 
619         public bool isGroupBy()
620         {
621             return groupBy;
622         }
623 
624         public void setGroupBy(bool groupBy)
625         {
626             this.groupBy = groupBy;
627         }
628 
629         public bool isHaving()
630         {
631             return having;
632         }
633 
634         public bool isJoin()
635         {
636             return join;
637         }
638 
639         public void setJoin(bool join)
640         {
641             this.join = join;
642         }
643 
644         public void setHaving(bool having)
645         {
646             this.having = having;
647         }
648 
649         public bool isPrimaryKey()
650         {
651             return primaryKey;
652         }
653 
654         public void setPrimaryKey(bool primaryKey)
655         {
656             this.primaryKey = primaryKey;
657         }
658 
659         public bool isUnique()
660         {
661             return unique;
662         }
663 
664         public void setUnique(bool unique)
665         {
666             this.unique = unique;
667         }
668 
669         public string getName()
670         {
671             return name;
672         }
673 
674         /**
675          * @since 1.0.20
676          */
677         public string getDataType()
678         {
679             return dataType;
680         }
681 
682         /**
683          * @since 1.0.20
684          */
685         public void setDataType(string dataType)
686         {
687             this.dataType = dataType;
688         }
689 
690         public Map!(string, Object) getAttributes()
691         {
692             return attributes;
693         }
694 
695         public void setAttributes(Map!(string, Object) attributes)
696         {
697             this.attributes = attributes;
698         }
699 
700         override public size_t toHash() @trusted nothrow
701         {
702             try{
703                 long hash = hashCode64();
704                 return cast(size_t)(hash ^ (hash >>> 32));
705             }catch(Exception e){}
706             return 0;
707         }
708 
709         override public string toString()
710         {
711             if (table !is null)
712             {
713                 return SQLUtils.normalize(table) ~ "." ~ SQLUtils.normalize(name);
714             }
715 
716             return SQLUtils.normalize(name);
717         }
718 
719         override public bool opEquals(Object obj)
720         {
721             if (!( cast(Column)obj !is null ))
722             {
723                 return false;
724             }
725 
726             Column column = cast(Column) obj;
727             return _hashCode64 == column._hashCode64;
728         }
729     }
730 
731         public static class Mode
732         {
733             __gshared Mode Insert;
734             __gshared Mode Update;
735             __gshared Mode Delete;
736             __gshared Mode Select;
737             __gshared Mode Merge;
738             __gshared Mode Truncate;
739             __gshared Mode Alter;
740             __gshared Mode Drop;
741             __gshared Mode DropIndex;
742             __gshared Mode CreateIndex;
743             __gshared Mode Replace;
744 
745             shared static this() {
746                 Insert = new Mode(1); //
747                 Update = new Mode(2); //
748                 Delete = new Mode(4); //
749                 Select = new Mode(8); //
750                 Merge = new Mode(16); //
751                 Truncate = new Mode(32); 
752                 Alter = new Mode(64); //
753                 Drop = new Mode(128); //
754                 DropIndex = new Mode(256);
755                 CreateIndex = new Mode(512);
756                 Replace = new Mode(1024);                
757             }
758 
759 
760             public int mark;
761 
762             private this(int mark)
763             {
764                 this.mark = mark;
765             }
766 
767             bool opEquals(const Mode h) nothrow
768             {
769                 return mark == h.mark;
770             }
771 
772             bool opEquals(ref const Mode h) nothrow
773             {
774                 return mark == h.mark;
775             }
776         }
777     }