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