EMMA Coverage Report (generated Sun Mar 01 22:06:14 CET 2015)
[all classes][org.h2.bnf.context]

COVERAGE SUMMARY FOR SOURCE FILE [DbContextRule.java]

nameclass, %method, %block, %line, %
DbContextRule.java100% (1/1)86%  (6/7)88%  (777/882)90%  (161.4/179)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class DbContextRule100% (1/1)86%  (6/7)88%  (777/882)90%  (161.4/179)
accept (BnfVisitor): void 0%   (0/1)0%   (0/1)0%   (0/1)
autoCompleteTableAlias (Sentence, boolean): String 100% (1/1)84%  (157/188)92%  (35.7/39)
autoComplete (Sentence): boolean 100% (1/1)87%  (457/523)88%  (91.7/104)
autoCompleteProcedure (Sentence): void 100% (1/1)96%  (149/156)96%  (27/28)
DbContextRule (DbContents, int): void 100% (1/1)100% (9/9)100% (4/4)
setColumnType (String): void 100% (1/1)100% (4/4)100% (2/2)
setLinks (HashMap): void 100% (1/1)100% (1/1)100% (1/1)

1/*
2 * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
3 * and the EPL 1.0 (http://h2database.com/html/license.html).
4 * Initial Developer: H2 Group
5 */
6package org.h2.bnf.context;
7 
8import java.util.HashMap;
9import java.util.HashSet;
10 
11import org.h2.bnf.Bnf;
12import org.h2.bnf.BnfVisitor;
13import org.h2.bnf.Rule;
14import org.h2.bnf.RuleElement;
15import org.h2.bnf.RuleHead;
16import org.h2.bnf.RuleList;
17import org.h2.bnf.Sentence;
18import org.h2.command.Parser;
19import org.h2.message.DbException;
20import org.h2.util.StringUtils;
21 
22/**
23 * A BNF terminal rule that is linked to the database context information.
24 * This class is used by the H2 Console, to support auto-complete.
25 */
26public class DbContextRule implements Rule {
27 
28    public static final int COLUMN = 0, TABLE = 1, TABLE_ALIAS = 2;
29    public static final int NEW_TABLE_ALIAS = 3;
30    public static final int COLUMN_ALIAS = 4, SCHEMA = 5, PROCEDURE = 6;
31 
32    private final DbContents contents;
33    private final int type;
34 
35    private String columnType;
36 
37    /**
38     * BNF terminal rule Constructor
39     * @param contents Extract rule from this component
40     * @param type Rule type, one of
41     * {@link DbContextRule#COLUMN},
42     * {@link DbContextRule#TABLE},
43     * {@link DbContextRule#TABLE_ALIAS},
44     * {@link DbContextRule#NEW_TABLE_ALIAS},
45     * {@link DbContextRule#COLUMN_ALIAS},
46     * {@link DbContextRule#SCHEMA}
47     */
48    public DbContextRule(DbContents contents, int type) {
49        this.contents = contents;
50        this.type = type;
51    }
52 
53    /**
54     * @param columnType COLUMN Auto completion can be filtered by column type
55     */
56    public void setColumnType(String columnType) {
57        this.columnType = columnType;
58    }
59 
60    @Override
61    public void setLinks(HashMap<String, RuleHead> ruleMap) {
62        // nothing to do
63    }
64 
65    @Override
66    public void accept(BnfVisitor visitor) {
67        // nothing to do
68    }
69 
70    @Override
71    public boolean autoComplete(Sentence sentence) {
72        String query = sentence.getQuery(), s = query;
73        String up = sentence.getQueryUpper();
74        switch (type) {
75        case SCHEMA: {
76            DbSchema[] schemas = contents.getSchemas();
77            String best = null;
78            DbSchema bestSchema = null;
79            for (DbSchema schema: schemas) {
80                String name = StringUtils.toUpperEnglish(schema.name);
81                if (up.startsWith(name)) {
82                    if (best == null || name.length() > best.length()) {
83                        best = name;
84                        bestSchema = schema;
85                    }
86                } else if (s.length() == 0 || name.startsWith(up)) {
87                    if (s.length() < name.length()) {
88                        sentence.add(name, name.substring(s.length()), type);
89                        sentence.add(schema.quotedName + ".",
90                                schema.quotedName.substring(s.length()) + ".",
91                                Sentence.CONTEXT);
92                    }
93                }
94            }
95            if (best != null) {
96                sentence.setLastMatchedSchema(bestSchema);
97                s = s.substring(best.length());
98            }
99            break;
100        }
101        case TABLE: {
102            DbSchema schema = sentence.getLastMatchedSchema();
103            if (schema == null) {
104                schema = contents.getDefaultSchema();
105            }
106            DbTableOrView[] tables = schema.getTables();
107            String best = null;
108            DbTableOrView bestTable = null;
109            for (DbTableOrView table : tables) {
110                String compare = up;
111                String name = StringUtils.toUpperEnglish(table.getName());
112                if (table.getQuotedName().length() > name.length()) {
113                    name = table.getQuotedName();
114                    compare = query;
115                }
116                if (compare.startsWith(name)) {
117                    if (best == null || name.length() > best.length()) {
118                        best = name;
119                        bestTable = table;
120                    }
121                } else if (s.length() == 0 || name.startsWith(compare)) {
122                    if (s.length() < name.length()) {
123                        sentence.add(table.getQuotedName(),
124                                table.getQuotedName().substring(s.length()),
125                                Sentence.CONTEXT);
126                    }
127                }
128            }
129            if (best != null) {
130                sentence.setLastMatchedTable(bestTable);
131                sentence.addTable(bestTable);
132                s = s.substring(best.length());
133            }
134            break;
135        }
136        case NEW_TABLE_ALIAS:
137            s = autoCompleteTableAlias(sentence, true);
138            break;
139        case TABLE_ALIAS:
140            s = autoCompleteTableAlias(sentence, false);
141            break;
142        case COLUMN_ALIAS: {
143            int i = 0;
144            if (query.indexOf(' ') < 0) {
145                break;
146            }
147            for (; i < up.length(); i++) {
148                char ch = up.charAt(i);
149                if (ch != '_' && !Character.isLetterOrDigit(ch)) {
150                    break;
151                }
152            }
153            if (i == 0) {
154                break;
155            }
156            String alias = up.substring(0, i);
157            if (Parser.isKeyword(alias, true)) {
158                break;
159            }
160            s = s.substring(alias.length());
161            break;
162        }
163        case COLUMN: {
164            HashSet<DbTableOrView> set = sentence.getTables();
165            String best = null;
166            DbTableOrView last = sentence.getLastMatchedTable();
167            if (last != null && last.getColumns() != null) {
168                for (DbColumn column : last.getColumns()) {
169                    String compare = up;
170                    String name = StringUtils.toUpperEnglish(column.getName());
171                    if (column.getQuotedName().length() > name.length()) {
172                        name = column.getQuotedName();
173                        compare = query;
174                    }
175                    if (compare.startsWith(name) &&
176                            (columnType == null ||
177                            column.getDataType().contains(columnType))) {
178                        String b = s.substring(name.length());
179                        if (best == null || b.length() < best.length()) {
180                            best = b;
181                        } else if (s.length() == 0 || name.startsWith(compare)) {
182                            if (s.length() < name.length()) {
183                                sentence.add(column.getName(),
184                                        column.getName().substring(s.length()),
185                                        Sentence.CONTEXT);
186                            }
187                        }
188                    }
189                }
190            }
191            for (DbSchema schema : contents.getSchemas()) {
192                for (DbTableOrView table : schema.getTables()) {
193                    if (table != last && set != null && !set.contains(table)) {
194                        continue;
195                    }
196                    if (table == null || table.getColumns() == null) {
197                        continue;
198                    }
199                    for (DbColumn column : table.getColumns()) {
200                        String name = StringUtils.toUpperEnglish(column
201                                .getName());
202                        if (columnType == null
203                                || column.getDataType().contains(columnType)) {
204                            if (up.startsWith(name)) {
205                                String b = s.substring(name.length());
206                                if (best == null || b.length() < best.length()) {
207                                    best = b;
208                                }
209                            } else if (s.length() == 0 || name.startsWith(up)) {
210                                if (s.length() < name.length()) {
211                                    sentence.add(column.getName(),
212                                            column.getName().substring(s.length()),
213                                            Sentence.CONTEXT);
214                                }
215                            }
216                        }
217                    }
218                }
219            }
220            if (best != null) {
221                s = best;
222            }
223            break;
224        }
225        case PROCEDURE:
226            autoCompleteProcedure(sentence);
227            break;
228        default:
229            throw DbException.throwInternalError("type=" + type);
230        }
231        if (!s.equals(query)) {
232            while (Bnf.startWithSpace(s)) {
233                s = s.substring(1);
234            }
235            sentence.setQuery(s);
236            return true;
237        }
238        return false;
239    }
240    private void autoCompleteProcedure(Sentence sentence) {
241        DbSchema schema = sentence.getLastMatchedSchema();
242        if (schema == null) {
243            schema = contents.getDefaultSchema();
244        }
245        String incompleteSentence = sentence.getQueryUpper();
246        String incompleteFunctionName = incompleteSentence;
247        if (incompleteSentence.contains("(")) {
248            incompleteFunctionName = incompleteSentence.substring(0,
249                    incompleteSentence.indexOf('(')).trim();
250        }
251 
252        // Common elements
253        RuleElement openBracket = new RuleElement("(", "Function");
254        RuleElement closeBracket = new RuleElement(")", "Function");
255        RuleElement comma = new RuleElement(",", "Function");
256 
257        // Fetch all elements
258        for (DbProcedure procedure : schema.getProcedures()) {
259            final String procName = procedure.getName();
260            if (procName.startsWith(incompleteFunctionName)) {
261                // That's it, build a RuleList from this function
262                RuleElement procedureElement = new RuleElement(procName,
263                        "Function");
264                RuleList rl = new RuleList(procedureElement, openBracket, false);
265                // Go further only if the user use open bracket
266                if (incompleteSentence.contains("(")) {
267                    for (DbColumn parameter : procedure.getParameters()) {
268                        if (parameter.getPosition() > 1) {
269                            rl = new RuleList(rl, comma, false);
270                        }
271                        DbContextRule columnRule = new DbContextRule(contents,
272                                COLUMN);
273                        String parameterType = parameter.getDataType();
274                        // Remove precision
275                        if (parameterType.contains("(")) {
276                            parameterType = parameterType.substring(0,
277                                    parameterType.indexOf('('));
278                        }
279                        columnRule.setColumnType(parameterType);
280                        rl = new RuleList(rl, columnRule, false);
281                    }
282                    rl = new RuleList(rl, closeBracket , false);
283                }
284                rl.autoComplete(sentence);
285            }
286        }
287    }
288 
289    private static String autoCompleteTableAlias(Sentence sentence,
290            boolean newAlias) {
291        String s = sentence.getQuery();
292        String up = sentence.getQueryUpper();
293        int i = 0;
294        for (; i < up.length(); i++) {
295            char ch = up.charAt(i);
296            if (ch != '_' && !Character.isLetterOrDigit(ch)) {
297                break;
298            }
299        }
300        if (i == 0) {
301            return s;
302        }
303        String alias = up.substring(0, i);
304        if ("SET".equals(alias) || Parser.isKeyword(alias, true)) {
305            return s;
306        }
307        if (newAlias) {
308            sentence.addAlias(alias, sentence.getLastTable());
309        }
310        HashMap<String, DbTableOrView> map = sentence.getAliases();
311        if ((map != null && map.containsKey(alias)) ||
312                (sentence.getLastTable() == null)) {
313            if (newAlias && s.length() == alias.length()) {
314                return s;
315            }
316            s = s.substring(alias.length());
317            if (s.length() == 0) {
318                sentence.add(alias + ".", ".", Sentence.CONTEXT);
319            }
320            return s;
321        }
322        HashSet<DbTableOrView> tables = sentence.getTables();
323        if (tables != null) {
324            String best = null;
325            for (DbTableOrView table : tables) {
326                String tableName =
327                        StringUtils.toUpperEnglish(table.getName());
328                if (alias.startsWith(tableName) &&
329                        (best == null || tableName.length() > best.length())) {
330                    sentence.setLastMatchedTable(table);
331                    best = tableName;
332                } else if (s.length() == 0 || tableName.startsWith(alias)) {
333                    sentence.add(tableName + ".",
334                            tableName.substring(s.length()) + ".",
335                            Sentence.CONTEXT);
336                }
337            }
338            if (best != null) {
339                s = s.substring(best.length());
340                if (s.length() == 0) {
341                    sentence.add(alias + ".", ".", Sentence.CONTEXT);
342                }
343                return s;
344            }
345        }
346        return s;
347    }
348 
349}

[all classes][org.h2.bnf.context]
EMMA 2.0.5312 (C) Vladimir Roubtsov