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.parser.SQLSelectListCache;
17 
18 import hunt.sql.ast.statement.SQLSelectQueryBlock;
19 // import entity.support.logging.Log;
20 // import entity.support.logging.LogFactory;
21 import hunt.sql.util.FnvHash;
22 import hunt.sql.parser.Lexer;
23 
24 import hunt.collection;
25 import hunt.sql.parser.SQLSelectParser;
26 import hunt.sql.parser.SQLParserUtils;
27 import hunt.String;
28 import hunt.sql.parser.Token;
29 import std.algorithm.searching;
30 import hunt.logging;
31 import hunt.text;
32 
33 public class SQLSelectListCache {
34     // private  static Log                LOG             = LogFactory.getLog(SQLSelectListCache.class);
35     private  string                    dbType;
36     private  List!(Entry)               entries;
37 
38     this()
39     {
40         entries         = new ArrayList!(Entry)();
41     }
42 
43     public this(string dbType) {
44         this();
45         this.dbType = dbType;
46     }
47 
48     public void add(string select) {
49         if (select is null || select.length == 0) {
50             return;
51         }
52 
53         SQLSelectParser selectParser = SQLParserUtils.createSQLStatementParser(select, dbType)
54                                                      .createSQLSelectParser();
55         SQLSelectQueryBlock queryBlock = SQLParserUtils.createSelectQueryBlock(dbType);
56         selectParser.accept(Token.SELECT);
57 
58         selectParser.parseSelectList(queryBlock);
59 
60         selectParser.accept(Token.FROM);
61         selectParser.accept(Token.EOF);
62 
63         string printSql = (cast(Object)(queryBlock)).toString();
64         long printSqlHash = FnvHash.fnv1a_64_lower(printSql);
65         entries.add(
66                 new Entry(select.substring(6)
67                         , queryBlock
68                         , printSql
69                         , printSqlHash)
70         );
71 
72         if (entries.size() > 5) {
73             warning("SelectListCache is too large.");
74         }
75     }
76 
77     public int getSize() {
78         return entries.size();
79     }
80 
81     public void clear() {
82         entries.clear();
83     }
84 
85     public bool match(Lexer lexer, SQLSelectQueryBlock queryBlock) {
86         if (lexer.token != Token.SELECT) {
87             return false;
88         }
89 
90         int pos = lexer.pos;
91         string text = lexer.text;
92 
93         for (int i = 0; i < entries.size(); i++) {
94             Entry entry = entries.get(i);
95             string block = entry.sql;
96             if (text.startsWith(block, pos)) {
97                 //SQLSelectQueryBlock queryBlockCached = queryBlockCache.get(i);
98                 // queryBlockCached.cloneSelectListTo(queryBlock);
99                 queryBlock.setCachedSelectList(entry.printSql, entry.printSqlHash);
100 
101                 int len = pos + cast(int)(block.length);
102                 lexer.reset(len, charAt(text, len), Token.FROM);
103                 return true;
104             }
105         }
106         return false;
107     }
108 
109     private static class Entry {
110         public  string              sql;
111         public  SQLSelectQueryBlock queryBlock;
112         public  string              printSql;
113         public  long                printSqlHash;
114 
115         public this(string sql, SQLSelectQueryBlock queryBlock, string printSql, long printSqlHash) {
116             this.sql = sql;
117             this.queryBlock = queryBlock;
118             this.printSql = printSql;
119             this.printSqlHash = printSqlHash;
120         }
121     }
122 }