use of org.jkiss.dbeaver.model.sql.parser.SQLWordPartDetector in project dbeaver by dbeaver.
the class SQLContextInformer method searchInformation.
public void searchInformation(IRegion region) {
ITextViewer textViewer = editor.getTextViewer();
final DBCExecutionContext executionContext = editor.getExecutionContext();
if (region == null || textViewer == null || executionContext == null) {
return;
}
IDocument document = textViewer.getDocument();
if (document == null) {
return;
}
SQLWordPartDetector wordDetector = new SQLWordPartDetector(document, syntaxManager, region.getOffset());
wordRegion = wordDetector.detectIdentifier(document, region);
if (wordRegion.word.length() == 0) {
return;
}
String fullName = wordRegion.identifier;
String tableName = wordRegion.word;
boolean caseSensitive = false;
if (wordDetector.isQuoted(tableName)) {
tableName = DBUtils.getUnQuotedIdentifier(tableName, syntaxManager.getIdentifierQuoteStrings());
caseSensitive = true;
}
String[] containerNames = null;
if (!CommonUtils.equalObjects(fullName, tableName)) {
int divPos = fullName.indexOf(syntaxManager.getStructSeparator());
if (divPos != -1) {
String[] parts = wordDetector.splitIdentifier(fullName);
tableName = parts[parts.length - 1];
containerNames = ArrayUtils.remove(String.class, parts, parts.length - 1);
for (int i = 0; i < containerNames.length; i++) {
if (wordDetector.isQuoted(containerNames[i])) {
containerNames[i] = DBUtils.getUnQuotedIdentifier(containerNames[i], syntaxManager.getIdentifierQuoteStrings());
}
containerNames[i] = DBObjectNameCaseTransformer.transformName(editor.getDataSource(), containerNames[i]);
}
if (wordDetector.isQuoted(tableName)) {
tableName = DBUtils.getUnQuotedIdentifier(tableName, syntaxManager.getIdentifierQuoteStrings());
}
} else {
// Full name could be quoted
if (wordDetector.isQuoted(fullName)) {
String unquotedName = DBUtils.getUnQuotedIdentifier(tableName, syntaxManager.getIdentifierQuoteStrings());
if (unquotedName.equals(tableName)) {
caseSensitive = true;
}
}
}
}
final SQLDialect dialect = syntaxManager.getDialect();
keywordType = dialect.getKeywordType(fullName);
if (keywordType == DBPKeywordType.KEYWORD && region.getLength() > 1) {
// It is a keyword = let's use whole selection
try {
fullName = document.get(region.getOffset(), region.getLength());
} catch (BadLocationException e) {
log.warn(e);
}
}
keywords = new String[] { fullName };
if (keywordType == DBPKeywordType.KEYWORD || keywordType == DBPKeywordType.FUNCTION) {
// Skip keywords
return;
}
final Map<String, ObjectLookupCache> contextCache = getLinksCache();
if (contextCache == null) {
return;
}
ObjectLookupCache tlc = contextCache.get(fullName);
if (tlc == null) {
// Start new word finder job
tlc = new ObjectLookupCache();
contextCache.put(fullName, tlc);
DBSStructureAssistant structureAssistant = DBUtils.getAdapter(DBSStructureAssistant.class, editor.getDataSource());
TablesFinderJob job = new TablesFinderJob(executionContext, structureAssistant, containerNames, tableName, caseSensitive, tlc);
job.schedule();
}
if (tlc.loading) {
// Wait for 1000ms maximum
for (int i = 0; i < 20; i++) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
// interrupted - just go further
break;
}
if (!tlc.loading) {
break;
}
Display.getCurrent().readAndDispatch();
}
}
if (!tlc.loading) {
synchronized (this) {
objectReferences = tlc.references;
}
}
}
use of org.jkiss.dbeaver.model.sql.parser.SQLWordPartDetector in project dbeaver by dbeaver.
the class SQLCompletionAnalyzer method runAnalyzer.
private void runAnalyzer() throws DBException {
String searchPrefix = request.getWordPart();
request.setQueryType(null);
SQLWordPartDetector wordDetector = request.getWordDetector();
SQLSyntaxManager syntaxManager = request.getContext().getSyntaxManager();
String prevKeyWord = wordDetector.getPrevKeyWord();
boolean isPrevWordEmpty = CommonUtils.isEmpty(wordDetector.getPrevWords());
String prevDelimiter = wordDetector.getPrevDelimiter();
{
if (!CommonUtils.isEmpty(prevKeyWord)) {
if (syntaxManager.getDialect().isEntityQueryWord(prevKeyWord)) {
// TODO: its an ugly hack. Need a better way
if (SQLConstants.KEYWORD_DELETE.equals(prevKeyWord)) {
request.setQueryType(null);
} else if (SQLConstants.KEYWORD_INTO.equals(prevKeyWord) && !isPrevWordEmpty && ("(".equals(prevDelimiter) || ",".equals(prevDelimiter))) {
request.setQueryType(SQLCompletionRequest.QueryType.COLUMN);
} else if (SQLConstants.KEYWORD_INTO.equals(prevKeyWord) && !isPrevWordEmpty && ("(*".equals(prevDelimiter) || "{*".equals(prevDelimiter) || "[*".equals(prevDelimiter))) {
wordDetector.shiftOffset(-SQLCompletionAnalyzer.ALL_COLUMNS_PATTERN.length());
searchPrefix = SQLCompletionAnalyzer.ALL_COLUMNS_PATTERN;
request.setQueryType(SQLCompletionRequest.QueryType.COLUMN);
} else if (SQLConstants.KEYWORD_JOIN.equals(prevKeyWord)) {
request.setQueryType(SQLCompletionRequest.QueryType.JOIN);
} else {
if (!isPrevWordEmpty && CommonUtils.isEmpty(prevDelimiter)) {
// Seems to be table alias
return;
}
request.setQueryType(SQLCompletionRequest.QueryType.TABLE);
}
} else if (syntaxManager.getDialect().isAttributeQueryWord(prevKeyWord)) {
request.setQueryType(SQLCompletionRequest.QueryType.COLUMN);
if (!request.isSimpleMode() && CommonUtils.isEmpty(request.getWordPart()) && prevDelimiter.equals(SQLCompletionAnalyzer.ALL_COLUMNS_PATTERN)) {
wordDetector.shiftOffset(-SQLCompletionAnalyzer.ALL_COLUMNS_PATTERN.length());
searchPrefix = SQLCompletionAnalyzer.ALL_COLUMNS_PATTERN;
}
} else if (SQLUtils.isExecQuery(syntaxManager.getDialect(), prevKeyWord)) {
request.setQueryType(SQLCompletionRequest.QueryType.EXEC);
}
}
}
request.setWordPart(searchPrefix);
DBPDataSource dataSource = request.getContext().getDataSource();
if (dataSource == null) {
return;
}
String wordPart = request.getWordPart();
boolean emptyWord = wordPart.length() == 0;
SQLCompletionRequest.QueryType queryType = request.getQueryType();
Map<String, Object> parameters = new LinkedHashMap<>();
List<String> prevWords = wordDetector.getPrevWords();
String previousWord = "";
if (!CommonUtils.isEmpty(prevWords)) {
previousWord = prevWords.get(0).toUpperCase(Locale.ENGLISH);
}
if (!CommonUtils.isEmpty(prevWords) && (SQLConstants.KEYWORD_PROCEDURE.equals(previousWord) || SQLConstants.KEYWORD_FUNCTION.equals(previousWord))) {
parameters.put(SQLCompletionProposalBase.PARAM_EXEC, false);
} else {
parameters.put(SQLCompletionProposalBase.PARAM_EXEC, true);
}
if (queryType != null) {
// or get list of root database objects
if (emptyWord) {
// Get root objects
DBPObject rootObject = null;
if (queryType == SQLCompletionRequest.QueryType.COLUMN && dataSource instanceof DBSObjectContainer) {
// Try to detect current table
rootObject = getTableFromAlias((DBSObjectContainer) dataSource, null, true);
if (rootObject instanceof DBSEntity) {
switch(prevKeyWord) {
case SQLConstants.KEYWORD_ON:
// Join?
if (makeJoinColumnProposals((DBSObjectContainer) dataSource, (DBSEntity) rootObject)) {
return;
}
// Fall-thru
case SQLConstants.KEYWORD_WHERE:
case SQLConstants.KEYWORD_AND:
case SQLConstants.KEYWORD_OR:
if (!request.isSimpleMode()) {
boolean waitsForValue = rootObject instanceof DBSEntity && !CommonUtils.isEmpty(prevWords) && !CommonUtils.isEmpty(prevDelimiter) && !prevDelimiter.endsWith(")");
if (waitsForValue) {
makeProposalsFromAttributeValues(dataSource, wordDetector, (DBSEntity) rootObject);
}
}
break;
}
}
} else if (dataSource instanceof DBSObjectContainer) {
// Try to get from active object
DBSObject selectedObject = DBUtils.getActiveInstanceObject(request.getContext().getExecutionContext());
if (selectedObject != null) {
makeProposalsFromChildren(selectedObject, null, false, parameters);
rootObject = DBUtils.getPublicObject(selectedObject.getParentObject());
} else {
rootObject = dataSource;
}
}
if (rootObject != null) {
makeProposalsFromChildren(rootObject, null, false, parameters);
}
if (queryType == SQLCompletionRequest.QueryType.JOIN && !proposals.isEmpty() && dataSource instanceof DBSObjectContainer) {
// Filter out non-joinable tables
DBSObject leftTable = getTableFromAlias((DBSObjectContainer) dataSource, null, true);
if (leftTable instanceof DBSEntity) {
filterNonJoinableProposals((DBSEntity) leftTable);
}
}
} else {
DBSObject rootObject = null;
if (queryType == SQLCompletionRequest.QueryType.COLUMN && dataSource instanceof DBSObjectContainer) {
// Part of column name
// Try to get from active object
DBSObjectContainer sc = (DBSObjectContainer) dataSource;
DBSObject selectedObject = DBUtils.getActiveInstanceObject(request.getContext().getExecutionContext());
if (selectedObject instanceof DBSObjectContainer) {
sc = (DBSObjectContainer) selectedObject;
}
SQLDialect sqlDialect = request.getContext().getDataSource().getSQLDialect();
String tableAlias = null;
if (ALL_COLUMNS_PATTERN.equals(wordPart)) {
if (!isPrevWordEmpty) {
if (!prevKeyWord.equalsIgnoreCase("INTO")) {
String prevWord = wordDetector.getPrevWords().get(0);
if (prevWord.contains(sqlDialect.getCatalogSeparator())) {
int divPos = prevWord.lastIndexOf(sqlDialect.getCatalogSeparator());
tableAlias = prevWord.substring(0, divPos);
}
}
}
}
if (tableAlias == null) {
int divPos = wordPart.lastIndexOf(syntaxManager.getStructSeparator());
tableAlias = divPos == -1 ? null : wordPart.substring(0, divPos);
}
if (tableAlias == null && !CommonUtils.isEmpty(wordPart)) {
// May be an incomplete table alias. Try to find such table
rootObject = getTableFromAlias(sc, wordPart, false);
if (rootObject != null) {
// Found alias - no proposals
searchFinished = true;
return;
}
}
rootObject = getTableFromAlias(sc, tableAlias, false);
if (rootObject == null && tableAlias != null) {
// Maybe alias ss a table name
String[] allNames = SQLUtils.splitFullIdentifier(tableAlias, sqlDialect.getCatalogSeparator(), sqlDialect.getIdentifierQuoteStrings(), false);
rootObject = SQLSearchUtils.findObjectByFQN(monitor, sc, request.getContext().getExecutionContext(), Arrays.asList(allNames), !request.isSimpleMode(), wordDetector);
}
}
if (rootObject != null) {
makeProposalsFromChildren(rootObject, wordPart, false, parameters);
} else {
// Get root object or objects from active database (if any)
if (queryType != SQLCompletionRequest.QueryType.COLUMN && queryType != SQLCompletionRequest.QueryType.EXEC) {
makeDataSourceProposals();
}
}
}
if (!request.isSimpleMode() && (queryType == SQLCompletionRequest.QueryType.EXEC || (queryType == SQLCompletionRequest.QueryType.COLUMN && request.getContext().isSearchProcedures())) && dataSource instanceof DBSObjectContainer) {
makeProceduresProposals(dataSource, wordPart, true);
}
} else {
if (!request.isSimpleMode() && !CommonUtils.isEmpty(prevWords)) {
if (SQLConstants.KEYWORD_PROCEDURE.equals(previousWord) || SQLConstants.KEYWORD_FUNCTION.equals(previousWord)) {
makeProceduresProposals(dataSource, wordPart, false);
}
// may be useful in the future for procedures autocomplete
/*if (SQLConstants.BLOCK_BEGIN.equalsIgnoreCase(prevWords.get(0))) {
makeProceduresProposals(dataSource, wordPart, true);
}*/
}
}
if (!emptyWord) {
makeProposalsFromQueryParts();
}
// Final filtering
if (!searchFinished) {
List<String> matchedKeywords = Collections.emptyList();
Set<String> allowedKeywords = null;
SQLDialect sqlDialect = request.getContext().getDataSource().getSQLDialect();
if (CommonUtils.isEmpty(prevKeyWord)) {
allowedKeywords = new HashSet<>();
Collections.addAll(allowedKeywords, sqlDialect.getQueryKeywords());
Collections.addAll(allowedKeywords, sqlDialect.getDMLKeywords());
Collections.addAll(allowedKeywords, sqlDialect.getDDLKeywords());
Collections.addAll(allowedKeywords, sqlDialect.getExecuteKeywords());
} else if (ArrayUtils.contains(sqlDialect.getQueryKeywords(), prevKeyWord.toUpperCase(Locale.ENGLISH))) {
// SELECT ..
// Limit with FROM if we already have some expression
String delimiter = wordDetector.getPrevDelimiter();
if (!isPrevWordEmpty && (CommonUtils.isEmpty(delimiter) || delimiter.endsWith(")"))) {
// last expression ends with space or with ")"
allowedKeywords = new HashSet<>();
allowedKeywords.add(SQLConstants.KEYWORD_FROM);
if (CommonUtils.isEmpty(request.getWordPart())) {
matchedKeywords = Arrays.asList(SQLConstants.KEYWORD_FROM);
}
}
} else if (sqlDialect.isEntityQueryWord(prevKeyWord)) {
allowedKeywords = new HashSet<>();
if (SQLConstants.KEYWORD_DELETE.equals(prevKeyWord)) {
allowedKeywords.add(SQLConstants.KEYWORD_FROM);
} else {
allowedKeywords.add(SQLConstants.KEYWORD_WHERE);
}
}
if (!CommonUtils.isEmpty(request.getWordPart())) {
// Keyword assist
matchedKeywords = syntaxManager.getDialect().getMatchedKeywords(request.getWordPart());
if (!request.isSimpleMode()) {
// Sort using fuzzy match
matchedKeywords.sort(Comparator.comparingInt(o -> TextUtils.fuzzyScore(o, request.getWordPart())));
}
}
for (String keyWord : matchedKeywords) {
DBPKeywordType keywordType = syntaxManager.getDialect().getKeywordType(keyWord);
if (keywordType != null) {
if (keywordType == DBPKeywordType.TYPE) {
continue;
}
if (request.getQueryType() == SQLCompletionRequest.QueryType.COLUMN && !(keywordType == DBPKeywordType.FUNCTION || keywordType == DBPKeywordType.KEYWORD || keywordType == DBPKeywordType.OTHER)) {
continue;
}
if (allowedKeywords != null && !allowedKeywords.contains(keyWord)) {
continue;
}
proposals.add(SQLCompletionAnalyzer.createCompletionProposal(request, keyWord, keyWord, keywordType, null, false, null, Collections.emptyMap()));
}
}
}
filterProposals(dataSource);
}
use of org.jkiss.dbeaver.model.sql.parser.SQLWordPartDetector in project dbeaver by dbeaver.
the class SQLCompletionAnalyzer method makeProposalsFromChildren.
private void makeProposalsFromChildren(DBPObject parent, @Nullable String startPart, boolean addFirst, Map<String, Object> params) throws DBException {
if (request.getQueryType() == SQLCompletionRequest.QueryType.EXEC) {
return;
}
if (parent instanceof DBSAlias) {
DBSObject realParent = ((DBSAlias) parent).getTargetObject(monitor);
if (realParent == null) {
log.debug("Can't get synonym target object");
} else {
parent = realParent;
}
}
SQLWordPartDetector wordDetector = request.getWordDetector();
if (startPart != null) {
startPart = wordDetector.removeQuotes(startPart).toUpperCase(Locale.ENGLISH);
int divPos = startPart.lastIndexOf(request.getContext().getSyntaxManager().getStructSeparator());
if (divPos != -1) {
startPart = startPart.substring(divPos + 1);
}
}
DBPDataSource dataSource = request.getContext().getDataSource();
Collection<? extends DBSObject> children = null;
if (parent instanceof DBSObjectContainer) {
children = ((DBSObjectContainer) parent).getChildren(monitor);
} else if (parent instanceof DBSEntity) {
children = ((DBSEntity) parent).getAttributes(monitor);
}
if (children != null && !children.isEmpty()) {
// boolean isJoin = SQLConstants.KEYWORD_JOIN.equals(request.wordDetector.getPrevKeyWord());
List<DBSObject> matchedObjects = new ArrayList<>();
final Map<String, Integer> scoredMatches = new HashMap<>();
boolean simpleMode = request.isSimpleMode();
boolean allObjects = !simpleMode && ALL_COLUMNS_PATTERN.equals(startPart);
String objPrefix = null;
if (allObjects) {
if (!CommonUtils.isEmpty(wordDetector.getPrevWords())) {
String prevWord = wordDetector.getPrevWords().get(0);
if (prevWord.length() > 0 && prevWord.charAt(prevWord.length() - 1) == request.getContext().getSyntaxManager().getStructSeparator()) {
objPrefix = prevWord;
}
}
}
StringBuilder combinedMatch = new StringBuilder();
for (DBSObject child : children) {
if (DBUtils.isHiddenObject(child)) {
// Skip hidden
continue;
}
if (DBUtils.isVirtualObject(child)) {
makeProposalsFromChildren(child, startPart, addFirst, Collections.emptyMap());
continue;
}
if (allObjects) {
if (combinedMatch.length() > 0) {
combinedMatch.append(", ");
if (objPrefix != null)
combinedMatch.append(objPrefix);
}
combinedMatch.append(DBUtils.getQuotedIdentifier(child));
} else {
if (dataSource != null && !request.getContext().isSearchInsideNames()) {
// startsWith
if (CommonUtils.isEmpty(startPart) || CommonUtils.startsWithIgnoreCase(child.getName(), startPart)) {
matchedObjects.add(child);
}
} else {
// Use fuzzy search for contains
int score = CommonUtils.isEmpty(startPart) ? 1 : TextUtils.fuzzyScore(child.getName(), startPart);
if (score > 0) {
matchedObjects.add(child);
scoredMatches.put(child.getName(), score);
}
}
}
}
if (combinedMatch.length() > 0) {
String replaceString = combinedMatch.toString();
proposals.add(createCompletionProposal(request, replaceString, replaceString, DBPKeywordType.OTHER, "All objects"));
} else if (!matchedObjects.isEmpty()) {
if (startPart == null || scoredMatches.isEmpty()) {
if (dataSource != null && request.getContext().isSortAlphabetically()) {
matchedObjects.sort(DBUtils.nameComparatorIgnoreCase());
}
} else {
matchedObjects.sort((o1, o2) -> {
int score1 = scoredMatches.get(o1.getName());
int score2 = scoredMatches.get(o2.getName());
if (score1 == score2) {
if (o1 instanceof DBSAttributeBase) {
return ((DBSAttributeBase) o1).getOrdinalPosition() - ((DBSAttributeBase) o2).getOrdinalPosition();
}
return o1.getName().compareToIgnoreCase(o2.getName());
}
return score2 - score1;
});
}
List<SQLCompletionProposalBase> childProposals = new ArrayList<>(matchedObjects.size());
for (DBSObject child : matchedObjects) {
SQLCompletionProposalBase proposal = makeProposalsFromObject(child, !(parent instanceof DBPDataSource), params);
if (!scoredMatches.isEmpty()) {
int proposalScore = scoredMatches.get(child.getName());
proposal.setProposalScore(proposalScore);
}
childProposals.add(proposal);
}
if (addFirst) {
// Add proposals in the beginning (because the most strict identifiers have to be first)
proposals.addAll(0, childProposals);
} else {
proposals.addAll(childProposals);
}
}
}
}
use of org.jkiss.dbeaver.model.sql.parser.SQLWordPartDetector in project dbeaver by dbeaver.
the class SQLCompletionAnalyzer method makeJoinColumnProposals.
private boolean makeJoinColumnProposals(DBSObjectContainer sc, DBSEntity leftTable) {
SQLWordPartDetector joinTableDetector = new SQLWordPartDetector(request.getDocument(), request.getContext().getSyntaxManager(), request.getWordDetector().getStartOffset(), 2);
List<String> prevWords = joinTableDetector.getPrevWords();
if (!CommonUtils.isEmpty(prevWords)) {
DBPDataSource dataSource = request.getContext().getDataSource();
SQLDialect sqlDialect = dataSource.getSQLDialect();
String rightTableName = prevWords.get(0);
String[] allNames = SQLUtils.splitFullIdentifier(rightTableName, sqlDialect.getCatalogSeparator(), sqlDialect.getIdentifierQuoteStrings(), false);
DBSObject rightTable = SQLSearchUtils.findObjectByFQN(monitor, sc, request.getContext().getExecutionContext(), Arrays.asList(allNames), !request.isSimpleMode(), request.getWordDetector());
if (rightTable instanceof DBSEntity) {
try {
String joinCriteria = SQLUtils.generateTableJoin(monitor, leftTable, DBUtils.getQuotedIdentifier(leftTable), (DBSEntity) rightTable, DBUtils.getQuotedIdentifier(rightTable));
proposals.add(createCompletionProposal(request, joinCriteria, joinCriteria, DBPKeywordType.OTHER, "Join condition"));
return true;
} catch (DBException e) {
log.error("Error generating join condition", e);
}
}
}
return false;
}
Aggregations