提交 71f69140 authored 作者: Thomas Mueller's avatar Thomas Mueller

H2 Console: improved autocomplete feature (also simplified the source code for this feature).

上级 efc3bd71
...@@ -280,7 +280,9 @@ public class Bnf { ...@@ -280,7 +280,9 @@ public class Bnf {
continue; continue;
} }
sentence.start(); sentence.start();
head.getRule().addNextTokenList(sentence); if (head.getRule().autoComplete(sentence)) {
break;
}
} }
return sentence.getNext(); return sentence.getNext();
} }
......
...@@ -28,23 +28,13 @@ public interface Rule { ...@@ -28,23 +28,13 @@ public interface Rule {
void setLinks(HashMap<String, RuleHead> ruleMap); void setLinks(HashMap<String, RuleHead> ruleMap);
/** /**
* Add the next possible token for a query. * Add the next possible token(s). If there was a match, the query in the
* Used for autocomplete support. * sentence is updated (the matched token is removed).
* *
* @param sentence the sentence context * @param sentence the sentence context
* @return true if a full match
*/ */
void addNextTokenList(Sentence sentence); boolean autoComplete(Sentence sentence);
/**
* Remove a token from a sentence. Used for autocomplete support.
* If there was a match, the query in the sentence is updated
* (the matched token is removed).
*
* @param sentence
* the sentence context
* @return false if not a match or a partial match, true if a full match
*/
boolean matchRemove(Sentence sentence);
/** /**
* Call the visit method in the given visitor. * Call the visit method in the given visitor.
......
...@@ -29,10 +29,6 @@ public class RuleElement implements Rule { ...@@ -29,10 +29,6 @@ public class RuleElement implements Rule {
this.type = topic.startsWith("function") ? Sentence.FUNCTION : Sentence.KEYWORD; this.type = topic.startsWith("function") ? Sentence.FUNCTION : Sentence.KEYWORD;
} }
public String toString() {
return name;
}
public void accept(BnfVisitor visitor) { public void accept(BnfVisitor visitor) {
visitor.visitRuleElement(keyword, name, link); visitor.visitRuleElement(keyword, name, link);
} }
...@@ -60,16 +56,14 @@ public class RuleElement implements Rule { ...@@ -60,16 +56,14 @@ public class RuleElement implements Rule {
throw new AssertionError("Unknown " + name + "/" + test); throw new AssertionError("Unknown " + name + "/" + test);
} }
public boolean matchRemove(Sentence sentence) { public boolean autoComplete(Sentence sentence) {
if (sentence.shouldStop()) { if (sentence.shouldStop()) {
return false; return false;
} }
String query = sentence.getQuery();
if (query.length() == 0) {
return false;
}
if (keyword) { if (keyword) {
String up = sentence.getQueryUpper(); String query = sentence.getQuery();
String q = query.trim();
String up = sentence.getQueryUpper().trim();
if (up.startsWith(name)) { if (up.startsWith(name)) {
query = query.substring(name.length()); query = query.substring(name.length());
while (!"_".equals(name) && query.length() > 0 && Character.isWhitespace(query.charAt(0))) { while (!"_".equals(name) && query.length() > 0 && Character.isWhitespace(query.charAt(0))) {
...@@ -77,38 +71,18 @@ public class RuleElement implements Rule { ...@@ -77,38 +71,18 @@ public class RuleElement implements Rule {
} }
sentence.setQuery(query); sentence.setQuery(query);
return true; return true;
} } else if (q.length() == 0 || name.startsWith(up)) {
return false;
}
if (!link.matchRemove(sentence)) {
return false;
}
if (name != null && !name.startsWith("@") && (link.name() == null || !link.name().startsWith("@"))) {
query = sentence.getQuery();
while (query.length() > 0 && Character.isWhitespace(query.charAt(0))) {
query = query.substring(1);
}
sentence.setQuery(query);
}
return true;
}
public void addNextTokenList(Sentence sentence) {
if (sentence.shouldStop()) {
return;
}
if (keyword) {
String query = sentence.getQuery();
String q = query.trim();
String up = sentence.getQueryUpper().trim();
if (q.length() == 0 || name.startsWith(up)) {
if (q.length() < name.length()) { if (q.length() < name.length()) {
sentence.add(name, name.substring(q.length()), type); sentence.add(name, name.substring(q.length()), type);
} }
} }
return; return false;
} }
link.addNextTokenList(sentence); return link.autoComplete(sentence);
}
public String toString() {
return name;
} }
} }
...@@ -12,6 +12,7 @@ import java.util.HashMap; ...@@ -12,6 +12,7 @@ import java.util.HashMap;
* Represents a hard coded terminal rule in a BNF object. * Represents a hard coded terminal rule in a BNF object.
*/ */
public class RuleFixed implements Rule { public class RuleFixed implements Rule {
public static final int YMD = 0, HMS = 1, NANOS = 2; public static final int YMD = 0, HMS = 1, NANOS = 2;
public static final int ANY_EXCEPT_SINGLE_QUOTE = 3; public static final int ANY_EXCEPT_SINGLE_QUOTE = 3;
public static final int ANY_EXCEPT_DOUBLE_QUOTE = 4; public static final int ANY_EXCEPT_DOUBLE_QUOTE = 4;
...@@ -28,41 +29,6 @@ public class RuleFixed implements Rule { ...@@ -28,41 +29,6 @@ public class RuleFixed implements Rule {
this.type = type; this.type = type;
} }
public String toString() {
switch(type) {
case YMD:
return "2000-01-01";
case HMS:
return "12:00";
case NANOS:
return "0";
case ANY_UNTIL_EOL:
case ANY_EXCEPT_SINGLE_QUOTE:
case ANY_EXCEPT_DOUBLE_QUOTE:
case ANY_WORD:
case ANY_EXCEPT_2_DOLLAR:
case ANY_UNTIL_END: {
return "XYZ";
}
case HEX_START:
return "0x";
case CONCAT:
return "||";
case AZ_UNDERSCORE:
return "A";
case AF:
return "F";
case DIGIT:
return "0";
case OPEN_BRACKET:
return "[";
case CLOSE_BRACKET:
return "]";
default:
throw new AssertionError("type="+type);
}
}
public void accept(BnfVisitor visitor) { public void accept(BnfVisitor visitor) {
visitor.visitRuleFixed(type); visitor.visitRuleFixed(type);
} }
...@@ -75,44 +41,35 @@ public class RuleFixed implements Rule { ...@@ -75,44 +41,35 @@ public class RuleFixed implements Rule {
// nothing to do // nothing to do
} }
public boolean matchRemove(Sentence sentence) { public boolean autoComplete(Sentence sentence) {
if (sentence.shouldStop()) { if (sentence.shouldStop()) {
return false; return false;
} }
String query = sentence.getQuery(); String query = sentence.getQuery();
if (query.length() == 0) {
return false;
}
String s = query; String s = query;
switch(type) { switch(type) {
case YMD: case YMD:
while (s.length() > 0 && "0123456789- ".indexOf(s.charAt(0)) >= 0) { while (s.length() > 0 && "0123456789- ".indexOf(s.charAt(0)) >= 0) {
s = s.substring(1); s = s.substring(1);
} }
if (s.length() == 0) {
sentence.add("2006-01-01", "1", Sentence.KEYWORD);
}
break; break;
case HMS: case HMS:
while (s.length() > 0 && "0123456789:. ".indexOf(s.charAt(0)) >= 0) { while (s.length() > 0 && "0123456789:. ".indexOf(s.charAt(0)) >= 0) {
s = s.substring(1); s = s.substring(1);
} }
if (s.length() == 0) {
sentence.add("12:00:00", "1", Sentence.KEYWORD);
}
break; break;
case NANOS: case NANOS:
while (s.length() > 0 && Character.isDigit(s.charAt(0))) { while (s.length() > 0 && Character.isDigit(s.charAt(0))) {
s = s.substring(1); s = s.substring(1);
} }
break; if (s.length() == 0) {
case ANY_WORD: sentence.add("nanoseconds", "0", Sentence.KEYWORD);
while (s.length() > 0 && Character.isWhitespace(s.charAt(0))) {
s = s.substring(1);
}
break;
case ANY_UNTIL_END:
while (s.length() > 1 && s.startsWith("*/")) {
s = s.substring(1);
}
break;
case ANY_UNTIL_EOL:
while (s.length() > 0 && s.charAt(0) != '\n') {
s = s.substring(1);
} }
break; break;
case ANY_EXCEPT_SINGLE_QUOTE: case ANY_EXCEPT_SINGLE_QUOTE:
...@@ -126,6 +83,22 @@ public class RuleFixed implements Rule { ...@@ -126,6 +83,22 @@ public class RuleFixed implements Rule {
break; break;
} }
} }
if (s.length() == 0) {
sentence.add("anything", "Hello World", Sentence.KEYWORD);
sentence.add("'", "'", Sentence.KEYWORD);
}
break;
case ANY_EXCEPT_2_DOLLAR:
while (true) {
while (s.length() > 0 && !s.startsWith("$$")) {
s = s.substring(1);
}
break;
}
if (s.length() == 0) {
sentence.add("anything", "Hello World", Sentence.KEYWORD);
sentence.add("$$", "$$", Sentence.KEYWORD);
}
break; break;
case ANY_EXCEPT_DOUBLE_QUOTE: case ANY_EXCEPT_DOUBLE_QUOTE:
while (true) { while (true) {
...@@ -138,13 +111,14 @@ public class RuleFixed implements Rule { ...@@ -138,13 +111,14 @@ public class RuleFixed implements Rule {
break; break;
} }
} }
if (s.length() == 0) {
sentence.add("anything", "identifier", Sentence.KEYWORD);
sentence.add("\"", "\"", Sentence.KEYWORD);
}
break; break;
case ANY_EXCEPT_2_DOLLAR: case ANY_WORD:
while (true) { while (s.length() > 0 && Character.isWhitespace(s.charAt(0))) {
while (s.length() > 0 && !s.startsWith("$$")) { s = s.substring(1);
s = s.substring(1);
}
break;
} }
break; break;
case HEX_START: case HEX_START:
...@@ -153,11 +127,23 @@ public class RuleFixed implements Rule { ...@@ -153,11 +127,23 @@ public class RuleFixed implements Rule {
} else if (s.startsWith("0")) { } else if (s.startsWith("0")) {
s = s.substring(1); s = s.substring(1);
} }
if (s.length() == 0) {
sentence.add("0x", "0x", Sentence.KEYWORD);
} else if ("0".equals(s)) {
sentence.add("0x", "x", Sentence.KEYWORD);
}
break; break;
case CONCAT: case CONCAT:
if (s.startsWith("||")) { if (s.equals("|")) {
sentence.add("||", "|", Sentence.KEYWORD);
} else if (s.startsWith("||")) {
s = s.substring(2); s = s.substring(2);
} else if (s.startsWith("|")) { } else if (s.length() == 0) {
sentence.add("||", "||", Sentence.KEYWORD);
}
break;
case ANY_UNTIL_EOL:
while (s.length() > 0 && s.charAt(0) != '\n') {
s = s.substring(1); s = s.substring(1);
} }
break; break;
...@@ -165,6 +151,9 @@ public class RuleFixed implements Rule { ...@@ -165,6 +151,9 @@ public class RuleFixed implements Rule {
if (s.length() > 0 && (Character.isLetter(s.charAt(0)) || s.charAt(0) == '_')) { if (s.length() > 0 && (Character.isLetter(s.charAt(0)) || s.charAt(0) == '_')) {
s = s.substring(1); s = s.substring(1);
} }
if (s.length() == 0) {
sentence.add("character", "A", Sentence.KEYWORD);
}
break; break;
case AF: case AF:
if (s.length() > 0) { if (s.length() > 0) {
...@@ -173,106 +162,47 @@ public class RuleFixed implements Rule { ...@@ -173,106 +162,47 @@ public class RuleFixed implements Rule {
s = s.substring(1); s = s.substring(1);
} }
} }
if (s.length() == 0) {
sentence.add("hex character", "0A", Sentence.KEYWORD);
}
break; break;
case DIGIT: case DIGIT:
if (s.length() > 0 && Character.isDigit(s.charAt(0))) { if (s.length() > 0 && Character.isDigit(s.charAt(0))) {
s = s.substring(1); s = s.substring(1);
} }
break; if (s.length() == 0) {
case OPEN_BRACKET:
s = s.substring(1);
break;
case CLOSE_BRACKET:
s = s.substring(1);
break;
default:
throw new AssertionError("type=" + type);
}
if (s.equals(query)) {
return false;
}
sentence.setQuery(s);
return true;
}
public void addNextTokenList(Sentence sentence) {
if (sentence.shouldStop()) {
return;
}
String query = sentence.getQuery();
switch(type) {
case YMD:
if (query.length() == 0) {
sentence.add("2006-01-01", "2006-01-01", Sentence.KEYWORD);
}
break;
case HMS:
if (query.length() == 0) {
sentence.add("12:00:00", "12:00:00", Sentence.KEYWORD);
}
break;
case NANOS:
if (query.length() == 0) {
sentence.add("nanoseconds", "0", Sentence.KEYWORD);
}
break;
case ANY_EXCEPT_SINGLE_QUOTE:
if (query.length() == 0) {
sentence.add("anything", "Hello World", Sentence.KEYWORD);
sentence.add("'", "'", Sentence.KEYWORD);
}
break;
case ANY_EXCEPT_2_DOLLAR:
if (query.length() == 0) {
sentence.add("anything", "Hello World", Sentence.KEYWORD);
sentence.add("'", "'", Sentence.KEYWORD);
}
break;
case ANY_EXCEPT_DOUBLE_QUOTE:
if (query.length() == 0) {
sentence.add("anything", "identifier", Sentence.KEYWORD);
}
break;
case ANY_WORD:
break;
case HEX_START:
if (query.length() == 0) {
sentence.add("0x", "0x", Sentence.KEYWORD);
} else if ("0".equals(query)) {
sentence.add("0x", "x", Sentence.KEYWORD);
}
break;
case CONCAT:
if (query.length() == 0) {
sentence.add("||", "||", Sentence.KEYWORD);
} else if ("|".equals(query)) {
sentence.add("||", "|", Sentence.KEYWORD);
}
break;
case AZ_UNDERSCORE:
if (query.length() == 0) {
sentence.add("character", "A", Sentence.KEYWORD);
}
break;
case AF:
if (query.length() == 0) {
sentence.add("hex character", "0A", Sentence.KEYWORD);
}
break;
case DIGIT:
if (query.length() == 0) {
sentence.add("digit", "1", Sentence.KEYWORD); sentence.add("digit", "1", Sentence.KEYWORD);
} }
break; break;
case OPEN_BRACKET: case OPEN_BRACKET:
sentence.add("[", "[", Sentence.KEYWORD); if (s.startsWith("[")) {
s = s.substring(1);
} else if (s.length() == 0) {
sentence.add("[", "[", Sentence.KEYWORD);
}
break; break;
case CLOSE_BRACKET: case CLOSE_BRACKET:
sentence.add("]", "]", Sentence.KEYWORD); if (s.startsWith("]")) {
s = s.substring(1);
} else if (s.length() == 0) {
sentence.add("]", "]", Sentence.KEYWORD);
}
break; break;
default: default:
throw new AssertionError("type="+type); throw new AssertionError("type="+type);
} }
if (!s.equals(query)) {
while (s.length() > 0 && Character.isWhitespace(s.charAt(0))) {
s = s.substring(1);
}
sentence.setQuery(s);
return true;
}
return false;
}
public String toString() {
return name();
} }
} }
...@@ -9,7 +9,6 @@ package org.h2.bnf; ...@@ -9,7 +9,6 @@ package org.h2.bnf;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import org.h2.util.New; import org.h2.util.New;
import org.h2.util.StatementBuilder;
/** /**
* Represents a sequence of BNF rules, or a list of alternative rules. * Represents a sequence of BNF rules, or a list of alternative rules.
...@@ -35,24 +34,6 @@ public class RuleList implements Rule { ...@@ -35,24 +34,6 @@ public class RuleList implements Rule {
this.or = or; this.or = or;
} }
public String toString() {
StatementBuilder buff = new StatementBuilder();
if (or) {
buff.append('{');
for (Rule r : list) {
buff.appendExceptFirst("|");
buff.append(r.toString());
}
buff.append('}');
} else {
for (Rule r : list) {
buff.appendExceptFirst(" ");
buff.append(r.toString());
}
}
return buff.toString();
}
public void accept(BnfVisitor visitor) { public void accept(BnfVisitor visitor) {
visitor.visitRuleList(or, list); visitor.visitRuleList(or, list);
} }
...@@ -70,43 +51,32 @@ public class RuleList implements Rule { ...@@ -70,43 +51,32 @@ public class RuleList implements Rule {
} }
} }
public boolean matchRemove(Sentence sentence) { public boolean autoComplete(Sentence sentence) {
String query = sentence.getQuery(); if (sentence.shouldStop()) {
if (query.length() == 0) {
return false; return false;
} }
String old = sentence.getQuery();
if (or) { if (or) {
for (Rule r : list) { for (Rule r : list) {
if (r.matchRemove(sentence)) { sentence.setQuery(old);
if (r.autoComplete(sentence)) {
return true; return true;
} }
} }
return false; return false;
}
for (Rule r : list) {
if (!r.matchRemove(sentence)) {
return false;
}
}
return true;
}
public void addNextTokenList(Sentence sentence) {
String old = sentence.getQuery();
if (or) {
for (Rule r : list) {
sentence.setQuery(old);
r.addNextTokenList(sentence);
}
} else { } else {
for (Rule r : list) { for (Rule r : list) {
r.addNextTokenList(sentence); if (!r.autoComplete(sentence)) {
if (!r.matchRemove(sentence)) { sentence.setQuery(old);
break; return false;
} }
} }
return true;
} }
sentence.setQuery(old); }
public String toString() {
return or ? "or: " : "" + list.toString();
} }
} }
...@@ -19,10 +19,6 @@ public class RuleOptional implements Rule { ...@@ -19,10 +19,6 @@ public class RuleOptional implements Rule {
this.rule = rule; this.rule = rule;
} }
public String toString() {
return "[" + rule.toString() + "]";
}
public void accept(BnfVisitor visitor) { public void accept(BnfVisitor visitor) {
visitor.visitRuleOptional(rule); visitor.visitRuleOptional(rule);
} }
...@@ -37,26 +33,16 @@ public class RuleOptional implements Rule { ...@@ -37,26 +33,16 @@ public class RuleOptional implements Rule {
mapSet = true; mapSet = true;
} }
} }
public boolean autoComplete(Sentence sentence) {
public boolean matchRemove(Sentence sentence) {
if (sentence.shouldStop()) { if (sentence.shouldStop()) {
return false; return false;
} }
String query = sentence.getQuery(); rule.autoComplete(sentence);
if (query.length() == 0) {
return true;
}
if (!rule.matchRemove(sentence)) {
return true;
}
return true; return true;
} }
public void addNextTokenList(Sentence sentence) { public String toString() {
if (sentence.shouldStop()) { return rule.toString();
return;
}
rule.addNextTokenList(sentence);
} }
} }
...@@ -21,10 +21,6 @@ public class RuleRepeat implements Rule { ...@@ -21,10 +21,6 @@ public class RuleRepeat implements Rule {
this.comma = comma; this.comma = comma;
} }
public String toString() {
return "...";
}
public void accept(BnfVisitor visitor) { public void accept(BnfVisitor visitor) {
visitor.visitRuleRepeat(comma, rule); visitor.visitRuleRepeat(comma, rule);
} }
...@@ -37,36 +33,18 @@ public class RuleRepeat implements Rule { ...@@ -37,36 +33,18 @@ public class RuleRepeat implements Rule {
// rule.setLinks(ruleMap); // rule.setLinks(ruleMap);
} }
public boolean matchRemove(Sentence sentence) { public boolean autoComplete(Sentence sentence) {
if (sentence.shouldStop()) { if (sentence.shouldStop()) {
return false; return false;
} }
String query = sentence.getQuery(); while (rule.autoComplete(sentence)) {
if (query.length() == 0) { // nothing to do
return false;
}
while (true) {
if (!rule.matchRemove(sentence)) {
return true;
}
if (sentence.getQuery().length() == 0) {
return true;
}
} }
return true;
} }
public void addNextTokenList(Sentence sentence) { public String toString() {
if (sentence.shouldStop()) { return rule.toString();
return;
}
String old = sentence.getQuery();
while (true) {
rule.addNextTokenList(sentence);
if (!rule.matchRemove(sentence) || old.equals(sentence.getQuery())) {
break;
}
}
sentence.setQuery(old);
} }
} }
...@@ -8,14 +8,12 @@ package org.h2.server.web; ...@@ -8,14 +8,12 @@ package org.h2.server.web;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map;
import org.h2.bnf.BnfVisitor; import org.h2.bnf.BnfVisitor;
import org.h2.bnf.Rule; import org.h2.bnf.Rule;
import org.h2.bnf.RuleHead; import org.h2.bnf.RuleHead;
import org.h2.bnf.Sentence; import org.h2.bnf.Sentence;
import org.h2.command.Parser; import org.h2.command.Parser;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.util.New;
import org.h2.util.StringUtils; import org.h2.util.StringUtils;
/** /**
...@@ -27,7 +25,6 @@ public class DbContextRule implements Rule { ...@@ -27,7 +25,6 @@ public class DbContextRule implements Rule {
static final int COLUMN = 0, TABLE = 1, TABLE_ALIAS = 2; static final int COLUMN = 0, TABLE = 1, TABLE_ALIAS = 2;
static final int NEW_TABLE_ALIAS = 3; static final int NEW_TABLE_ALIAS = 3;
static final int COLUMN_ALIAS = 4, SCHEMA = 5; static final int COLUMN_ALIAS = 4, SCHEMA = 5;
private static final boolean SUGGEST_TABLE_ALIAS = false;
private DbContents contents; private DbContents contents;
private int type; private int type;
...@@ -64,332 +61,157 @@ public class DbContextRule implements Rule { ...@@ -64,332 +61,157 @@ public class DbContextRule implements Rule {
// nothing to do // nothing to do
} }
public void addNextTokenList(Sentence sentence) { public void accept(BnfVisitor visitor) {
switch (type) { // nothing to do
case SCHEMA:
addSchema(sentence);
break;
case TABLE:
addTable(sentence);
break;
case NEW_TABLE_ALIAS:
addNewTableAlias(sentence);
break;
case TABLE_ALIAS:
addTableAlias(sentence);
break;
case COLUMN_ALIAS:
// addColumnAlias(query, sentence);
// break;
case COLUMN:
addColumn(sentence);
break;
default:
}
} }
private void addTableAlias(Sentence sentence) { public boolean autoComplete(Sentence sentence) {
String query = sentence.getQuery(); String query = sentence.getQuery(), s = query;
String q = StringUtils.toUpperEnglish(query.trim()); String up = sentence.getQueryUpper();
HashMap<String, DbTableOrView> map = sentence.getAliases(); switch (type) {
HashSet<String> set = New.hashSet(); case SCHEMA: {
if (map != null) { DbSchema[] schemas = contents.schemas;
for (Map.Entry<String, DbTableOrView> entry : map.entrySet()) { String best = null;
String alias = entry.getKey(); DbSchema bestSchema = null;
DbTableOrView table = entry.getValue(); for (DbSchema schema: schemas) {
set.add(StringUtils.toUpperEnglish(table.name)); String name = StringUtils.toUpperEnglish(schema.name);
if (q.length() == 0 || alias.startsWith(q)) { if (up.startsWith(name)) {
if (q.length() < alias.length()) { if (best == null || name.length() > best.length()) {
sentence.add(alias + ".", alias.substring(q.length()) + ".", Sentence.CONTEXT); best = name;
bestSchema = schema;
} }
} } else if (s.length() == 0 || name.startsWith(up)) {
} if (s.length() < name.length()) {
} sentence.add(name, name.substring(s.length()), type);
HashSet<DbTableOrView> tables = sentence.getTables(); sentence.add(schema.quotedName + ".", schema.quotedName.substring(s.length()) + ".", Sentence.CONTEXT);
if (tables != null) {
for (DbTableOrView table : tables) {
String tableName = StringUtils.toUpperEnglish(table.name);
//DbTableOrView[] tables = contents.defaultSchema.tables;
//for(int i=0; i<tables.length; i++) {
// DbTableOrView table = tables[i];
// String tableName = StringUtils.toUpperEnglish(table.name);
if (!set.contains(tableName)) {
if (q.length() == 0 || tableName.startsWith(q)) {
if (q.length() < tableName.length()) {
sentence.add(tableName + ".", tableName.substring(q.length()) + ".", Sentence.CONTEXT);
}
} }
} }
} }
} if (best != null) {
} sentence.setLastMatchedSchema(bestSchema);
s = s.substring(best.length());
private void addNewTableAlias(Sentence sentence) {
if (SUGGEST_TABLE_ALIAS) {
// good for testing!
String query = sentence.getQuery();
if (query.length() > 3) {
return;
} }
String lastTableName = StringUtils.toUpperEnglish(sentence.getLastTable().name); break;
if (lastTableName == null) { }
return; case TABLE: {
DbSchema schema = sentence.getLastMatchedSchema();
if (schema == null) {
schema = contents.defaultSchema;
} }
HashMap<String, DbTableOrView> map = sentence.getAliases(); DbTableOrView[] tables = schema.tables;
String shortName = lastTableName.substring(0, 1); String best = null;
if (map != null && map.containsKey(shortName)) { DbTableOrView bestTable = null;
int result = 0; for (DbTableOrView table : tables) {
for (int i = 1;; i++) { String name = StringUtils.toUpperEnglish(table.name);
if (!map.containsKey(shortName + i)) { if (up.startsWith(name)) {
result = i; if (best == null || name.length() > best.length()) {
break; best = name;
bestTable = table;
}
} else if (s.length() == 0 || name.startsWith(up)) {
if (s.length() < name.length()) {
sentence.add(table.quotedName, table.quotedName.substring(s.length()), Sentence.CONTEXT);
} }
} }
shortName += result;
} }
String q = StringUtils.toUpperEnglish(query.trim()); if (best != null) {
if (q.length() == 0 || StringUtils.toUpperEnglish(shortName).startsWith(q)) { sentence.setLastMatchedTable(bestTable);
if (q.length() < shortName.length()) { sentence.addTable(bestTable);
sentence.add(shortName, shortName.substring(q.length()), Sentence.CONTEXT); s = s.substring(best.length());
}
} }
break;
} }
} case NEW_TABLE_ALIAS:
s = autoCompleteTableAlias(sentence, true);
// private boolean startWithIgnoreCase(String a, String b) { break;
// if(a.length() < b.length()) { case TABLE_ALIAS:
// return false; s = autoCompleteTableAlias(sentence, false);
// } break;
// for(int i=0; i<b.length(); i++) { case COLUMN_ALIAS: {
// if(Character.toUpperCase(a.charAt(i)) int i = 0;
// != Character.toUpperCase(b.charAt(i))) { if (query.indexOf(' ') < 0) {
// return false; break;
// }
// }
// return true;
// }
private void addSchema(Sentence sentence) {
String query = sentence.getQuery();
String q = StringUtils.toUpperEnglish(query);
if (q.trim().length() == 0) {
q = q.trim();
}
for (DbSchema schema : contents.schemas) {
if (schema == contents.defaultSchema) {
continue;
} }
if (q.length() == 0 || StringUtils.toUpperEnglish(schema.name).startsWith(q)) { for (; i < up.length(); i++) {
if (q.length() < schema.quotedName.length()) { char ch = up.charAt(i);
sentence.add(schema.quotedName + ".", schema.quotedName.substring(q.length()) + ".", Sentence.CONTEXT); if (ch != '_' && !Character.isLetterOrDigit(ch)) {
break;
} }
} }
} if (i == 0) {
} break;
private void addTable(Sentence sentence) {
String query = sentence.getQuery();
DbSchema schema = sentence.getLastMatchedSchema();
if (schema == null) {
schema = contents.defaultSchema;
}
String q = StringUtils.toUpperEnglish(query);
if (q.trim().length() == 0) {
q = q.trim();
}
for (DbTableOrView table : schema.tables) {
if (q.length() == 0 || StringUtils.toUpperEnglish(table.name).startsWith(q)) {
if (q.length() < table.quotedName.length()) {
sentence.add(table.quotedName, table.quotedName.substring(q.length()), Sentence.CONTEXT);
}
}
}
}
private void addColumn(Sentence sentence) {
String query = sentence.getQuery();
String tableName = query;
String columnPattern = "";
if (query.trim().length() == 0) {
tableName = null;
} else {
tableName = StringUtils.toUpperEnglish(query.trim());
if (tableName.endsWith(".")) {
tableName = tableName.substring(0, tableName.length() - 1);
} else {
columnPattern = StringUtils.toUpperEnglish(query.trim());
tableName = null;
}
}
HashSet<DbTableOrView> set = null;
HashMap<String, DbTableOrView> aliases = sentence.getAliases();
if (tableName == null && sentence.getTables() != null) {
set = sentence.getTables();
}
DbTableOrView table = null;
if (tableName != null && aliases != null && aliases.get(tableName) != null) {
table = aliases.get(tableName);
tableName = StringUtils.toUpperEnglish(table.name);
}
if (tableName == null) {
if (set == null && aliases == null) {
return;
}
if ((set != null && set.size() > 1) || (aliases != null && aliases.size() > 1)) {
return;
} }
} String alias = up.substring(0, i);
if (table == null) { if (Parser.isKeyword(alias, true)) {
for (DbTableOrView tab : contents.defaultSchema.tables) {
String t = StringUtils.toUpperEnglish(tab.name);
if (tableName != null && !tableName.equals(t)) {
continue;
}
if (set != null && !set.contains(tab)) {
continue;
}
table = tab;
break; break;
} }
s = s.substring(alias.length());
break;
} }
if (table != null && table.columns != null) { case COLUMN: {
for (DbColumn column : table.columns) { HashSet<DbTableOrView> set = sentence.getTables();
String columnName = column.name; String best = null;
if (!StringUtils.toUpperEnglish(columnName).startsWith(columnPattern)) { DbTableOrView last = sentence.getLastMatchedTable();
continue; if (last != null && last.columns != null) {
} for (DbColumn column : last.columns) {
if (columnPattern.length() < columnName.length()) { String name = StringUtils.toUpperEnglish(column.name);
String sub = columnName.substring(columnPattern.length()); if (up.startsWith(name)) {
if (sub.equals(columnName) && contents.needsQuotes(columnName)) { String b = s.substring(name.length());
columnName = StringUtils.quoteIdentifier(columnName); if (best == null || b.length() < best.length()) {
sub = columnName; best = b;
} else if (s.length() == 0 || name.startsWith(up)) {
if (s.length() < name.length()) {
sentence.add(column.name, column.name.substring(s.length()), Sentence.CONTEXT);
}
}
} }
sentence.add(columnName, sub, Sentence.CONTEXT);
} }
} }
} for (DbSchema schema : contents.schemas) {
} for (DbTableOrView table : schema.tables) {
if (table != last && set != null && !set.contains(table)) {
public boolean matchRemove(Sentence sentence) { continue;
if (sentence.getQuery().length() == 0) { }
return false; if (table == null || table.columns == null) {
} continue;
String s; }
switch (type) { for (DbColumn column : table.columns) {
case SCHEMA: String name = StringUtils.toUpperEnglish(column.name);
s = matchSchema(sentence); if (up.startsWith(name)) {
break; String b = s.substring(name.length());
case TABLE: if (best == null || b.length() < best.length()) {
s = matchTable(sentence); best = b;
break; }
case NEW_TABLE_ALIAS: } else if (s.length() == 0 || name.startsWith(up)) {
s = matchTableAlias(sentence, true); if (s.length() < name.length()) {
break; sentence.add(column.name, column.name.substring(s.length()), Sentence.CONTEXT);
case TABLE_ALIAS: }
s = matchTableAlias(sentence, false); }
break; }
case COLUMN_ALIAS:
s = matchColumnAlias(sentence);
break;
case COLUMN:
s = matchColumn(sentence);
break;
default:
throw DbException.throwInternalError("type=" + type);
}
if (s == null) {
return false;
}
sentence.setQuery(s);
return true;
}
private String matchSchema(Sentence sentence) {
String query = sentence.getQuery();
String up = sentence.getQueryUpper();
DbSchema[] schemas = contents.schemas;
String best = null;
DbSchema bestSchema = null;
for (DbSchema schema: schemas) {
String schemaName = StringUtils.toUpperEnglish(schema.name);
if (up.startsWith(schemaName)) {
if (best == null || schemaName.length() > best.length()) {
best = schemaName;
bestSchema = schema;
} }
} }
} if (best != null) {
sentence.setLastMatchedSchema(bestSchema); s = best;
if (best == null) {
return null;
}
query = query.substring(best.length());
// while(query.length()>0 && Character.isWhitespace(query.charAt(0))) {
// query = query.substring(1);
// }
return query;
}
private String matchTable(Sentence sentence) {
String query = sentence.getQuery();
String up = sentence.getQueryUpper();
DbSchema schema = sentence.getLastMatchedSchema();
if (schema == null) {
schema = contents.defaultSchema;
}
DbTableOrView[] tables = schema.tables;
String best = null;
DbTableOrView bestTable = null;
for (DbTableOrView table : tables) {
String tableName = StringUtils.toUpperEnglish(table.name);
if (up.startsWith(tableName)) {
if (best == null || tableName.length() > best.length()) {
best = tableName;
bestTable = table;
}
} }
break;
} }
if (best == null) { default:
return null; throw DbException.throwInternalError("type=" + type);
}
sentence.addTable(bestTable);
query = query.substring(best.length());
// while(query.length()>0 && Character.isWhitespace(query.charAt(0))) {
// query = query.substring(1);
// }
return query;
}
private String matchColumnAlias(Sentence sentence) {
String query = sentence.getQuery();
String up = sentence.getQueryUpper();
int i = 0;
if (query.indexOf(' ') < 0) {
return null;
} }
for (; i < up.length(); i++) { if (!s.equals(query)) {
char ch = up.charAt(i); while (s.length() > 0 && Character.isWhitespace(s.charAt(0))) {
if (ch != '_' && !Character.isLetterOrDigit(ch)) { s = s.substring(1);
break;
} }
sentence.setQuery(s);
return true;
} }
if (i == 0) { return false;
return null;
}
String alias = up.substring(0, i);
if (Parser.isKeyword(alias, true)) {
return null;
}
return query.substring(alias.length());
} }
private String matchTableAlias(Sentence sentence, boolean add) { private String autoCompleteTableAlias(Sentence sentence, boolean newAlias) {
String query = sentence.getQuery(); String s = sentence.getQuery();
String up = sentence.getQueryUpper(); String up = sentence.getQueryUpper();
int i = 0; int i = 0;
if (query.indexOf(' ') < 0) {
return null;
}
for (; i < up.length(); i++) { for (; i < up.length(); i++) {
char ch = up.charAt(i); char ch = up.charAt(i);
if (ch != '_' && !Character.isLetterOrDigit(ch)) { if (ch != '_' && !Character.isLetterOrDigit(ch)) {
...@@ -397,84 +219,47 @@ public class DbContextRule implements Rule { ...@@ -397,84 +219,47 @@ public class DbContextRule implements Rule {
} }
} }
if (i == 0) { if (i == 0) {
return null; return s;
} }
String alias = up.substring(0, i); String alias = up.substring(0, i);
if (Parser.isKeyword(alias, true)) { if ("SET".equals(alias) || Parser.isKeyword(alias, true)) {
return null; return s;
} }
if (add) { if (newAlias) {
sentence.addAlias(alias, sentence.getLastTable()); sentence.addAlias(alias, sentence.getLastTable());
} }
HashMap<String, DbTableOrView> map = sentence.getAliases(); HashMap<String, DbTableOrView> map = sentence.getAliases();
if ((map != null && map.containsKey(alias)) || (sentence.getLastTable() == null)) { if ((map != null && map.containsKey(alias)) || (sentence.getLastTable() == null)) {
if (add && query.length() == alias.length()) { if (newAlias && s.length() == alias.length()) {
return query; return s;
} }
query = query.substring(alias.length()); s = s.substring(alias.length());
return query; if (s.length() == 0) {
sentence.add(alias + ".", ".", Sentence.CONTEXT);
}
return s;
} }
HashSet<DbTableOrView> tables = sentence.getTables(); HashSet<DbTableOrView> tables = sentence.getTables();
if (tables != null) { if (tables != null) {
String best = null; String best = null;
for (DbTableOrView table : tables) { for (DbTableOrView table : tables) {
String tableName = StringUtils.toUpperEnglish(table.name); String tableName = StringUtils.toUpperEnglish(table.name);
//DbTableOrView[] tables = contents.defaultSchema.tables;
//for(int i=0; i<tables.length; i++) {
// DbTableOrView table = tables[i];
// String tableName = StringUtils.toUpperEnglish(table.name);
if (alias.startsWith(tableName) && (best == null || tableName.length() > best.length())) { if (alias.startsWith(tableName) && (best == null || tableName.length() > best.length())) {
sentence.setLastMatchedTable(table); sentence.setLastMatchedTable(table);
best = tableName; best = tableName;
} else if (s.length() == 0 || tableName.startsWith(alias)) {
sentence.add(tableName + ".", tableName.substring(s.length()) + ".", Sentence.CONTEXT);
} }
} }
if (best != null) { if (best != null) {
query = query.substring(best.length()); s = s.substring(best.length());
return query; if (s.length() == 0) {
} sentence.add(alias + ".", ".", Sentence.CONTEXT);
}
return null;
}
private String matchColumn(Sentence sentence) {
String query = sentence.getQuery();
String up = sentence.getQueryUpper();
HashSet<DbTableOrView> set = sentence.getTables();
String best = null;
DbTableOrView last = sentence.getLastMatchedTable();
if (last != null && last.columns != null) {
for (DbColumn column : last.columns) {
String name = StringUtils.toUpperEnglish(column.name);
if (up.startsWith(name)) {
String b = query.substring(name.length());
if (best == null || b.length() < best.length()) {
best = b;
}
}
}
}
for (DbTableOrView table : contents.defaultSchema.tables) {
if (table != last && set != null && !set.contains(table)) {
continue;
}
if (table == null || table.columns == null) {
continue;
}
for (DbColumn column : table.columns) {
String name = StringUtils.toUpperEnglish(column.name);
if (up.startsWith(name)) {
String b = query.substring(name.length());
if (best == null || b.length() < best.length()) {
best = b;
}
} }
return s;
} }
} }
return best; return s;
}
public void accept(BnfVisitor visitor) {
// nothing to do
} }
} }
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论