private SQLCompletionProposal makeProposalsFromObject( DBPNamedObject object, @Nullable DBPImage objectIcon) { String objectName = DBUtils.getObjectFullName(object); StringBuilder info = new StringBuilder(); PropertyCollector collector = new PropertyCollector(object, false); collector.collectProperties(); for (DBPPropertyDescriptor descriptor : collector.getPropertyDescriptors2()) { Object propValue = collector.getPropertyValue(descriptor.getId()); if (propValue == null) { continue; } String propString = propValue.toString(); info.append("<b>").append(descriptor.getDisplayName()).append(": </b>"); info.append(propString); info.append("<br>"); } boolean isSingleObject = true; String replaceString = null; DBPDataSource dataSource = editor.getDataSource(); if (dataSource != null) { // If we replace short name with referenced object // and current active schema (catalog) is not this object's container then // replace with full qualified name if (!getPreferences().getBoolean(SQLPreferenceConstants.PROPOSAL_SHORT_NAME) && object instanceof DBSObjectReference) { if (wordDetector.getFullWord().indexOf(editor.getSyntaxManager().getStructSeparator()) == -1) { DBSObjectReference structObject = (DBSObjectReference) object; if (structObject.getContainer() != null) { DBSObject selectedObject = getSelectedObject(dataSource); if (selectedObject != structObject.getContainer()) { replaceString = DBUtils.getFullQualifiedName(dataSource, structObject.getContainer(), object); isSingleObject = false; } } } } if (replaceString == null) { replaceString = DBUtils.getQuotedIdentifier(dataSource, object.getName()); } } else { replaceString = DBUtils.getObjectShortName(object); } return createCompletionProposal( replaceString, objectName, info.toString(), objectIcon, isSingleObject, object); }
@Nullable private static DBSObject getSelectedObject(DBPDataSource dataSource) { DBSObjectSelector objectSelector = DBUtils.getAdapter(DBSObjectSelector.class, dataSource); if (objectSelector != null) { return objectSelector.getSelectedObject(); } return null; }
private static boolean equalObjects(DBSObject object1, DBSObject object2) { if (object1 == object2) { return true; } if (object1 == null || object2 == null) { return false; } while (object1 != null && object2 != null) { if (object1.getClass() != object2.getClass() || !CommonUtils.equalObjects( DBUtils.getObjectUniqueName(object1), DBUtils.getObjectUniqueName(object2))) { return false; } object1 = object1.getParentObject(); object2 = object2.getParentObject(); } return true; }
/* * Turns the vector into an Array of ICompletionProposal objects */ protected SQLCompletionProposal createCompletionProposal( String replaceString, String displayString, String description, @Nullable DBPImage image, boolean isObject, @Nullable DBPNamedObject object) { DBPPreferenceStore store = getPreferences(); DBPDataSource dataSource = editor.getDataSource(); if (dataSource != null) { if (isObject) { // Escape replace string if required replaceString = DBUtils.getQuotedIdentifier(dataSource, replaceString); } } // If we have quoted string then ignore pref settings boolean quotedString = wordDetector.isQuoted(replaceString); final int proposalCase = quotedString ? SQLPreferenceConstants.PROPOSAL_CASE_DEFAULT : store.getInt(SQLPreferenceConstants.PROPOSAL_INSERT_CASE); switch (proposalCase) { case SQLPreferenceConstants.PROPOSAL_CASE_UPPER: replaceString = replaceString.toUpperCase(); break; case SQLPreferenceConstants.PROPOSAL_CASE_LOWER: replaceString = replaceString.toLowerCase(); break; default: DBPIdentifierCase convertCase = quotedString && dataSource instanceof SQLDataSource ? ((SQLDataSource) dataSource).getSQLDialect().storesQuotedCase() : DBPIdentifierCase.MIXED; replaceString = convertCase.transform(replaceString); break; } Image img = image == null ? null : DBeaverIcons.getImage(image); return new SQLCompletionProposal( editor.getSyntaxManager(), displayString, replaceString, // replacementString wordDetector, // wordDetector replaceString.length(), // cursorPosition the position of the cursor following the insert // relative to replacementOffset img, // image to display new ContextInformation( img, displayString, displayString), // the context information associated with this proposal description, object); }
@Nullable private DBSObject getTableFromAlias( DBRProgressMonitor monitor, DBSObjectContainer sc, @Nullable String token) { final DBPDataSource dataSource = editor.getDataSource(); if (!(dataSource instanceof SQLDataSource)) { return null; } if (activeQuery == null) { activeQuery = editor.extractQueryAtPos(documentOffset).getQuery() + " "; } final List<String> nameList = new ArrayList<>(); if (token == null) { token = ""; } { Matcher matcher; Pattern aliasPattern; SQLDialect sqlDialect = ((SQLDataSource) dataSource).getSQLDialect(); String quoteString = sqlDialect.getIdentifierQuoteString(); String quote = quoteString == null ? SQLConstants.STR_QUOTE_DOUBLE : SQLConstants.STR_QUOTE_DOUBLE.equals(quoteString) ? quoteString : Pattern.quote(quoteString); String catalogSeparator = sqlDialect.getCatalogSeparator(); while (token.endsWith(catalogSeparator)) token = token.substring(0, token.length() - 1); String tableNamePattern = "((?:" + quote + "(?:[.[^" + quote + "]]+)" + quote + ")|(?:[\\w" + Pattern.quote(catalogSeparator) + "]+))"; String structNamePattern; if (CommonUtils.isEmpty(token)) { structNamePattern = "(?:from|update|join|into)\\s*" + tableNamePattern; } else { structNamePattern = tableNamePattern + "(?:\\s*\\.\\s*" + tableNamePattern + ")?" + "\\s+(?:(?:AS)\\s)?" + token + "[\\s,]+"; } try { aliasPattern = Pattern.compile(structNamePattern, Pattern.CASE_INSENSITIVE); } catch (PatternSyntaxException e) { // Bad pattern - seems to be a bad token return null; } matcher = aliasPattern.matcher(activeQuery); if (!matcher.find()) { return null; } int groupCount = matcher.groupCount(); for (int i = 1; i <= groupCount; i++) { String group = matcher.group(i); if (!CommonUtils.isEmpty(group)) { String[] allNames = group.split(Pattern.quote(catalogSeparator)); for (String name : allNames) { if (quoteString != null && name.startsWith(quoteString) && name.endsWith(quoteString)) { name = name.substring(1, name.length() - 1); } nameList.add(name); } } } } if (nameList.isEmpty()) { return null; } for (int i = 0; i < nameList.size(); i++) { nameList.set( i, DBObjectNameCaseTransformer.transformName(sc.getDataSource(), nameList.get(i))); } try { DBSObject childObject = null; while (childObject == null) { childObject = DBUtils.findNestedObject(monitor, sc, nameList); if (childObject == null) { DBSObjectContainer parentSc = DBUtils.getParentAdapter(DBSObjectContainer.class, sc); if (parentSc == null) { break; } sc = parentSc; } } if (childObject == null && nameList.size() <= 1) { // No such object found - may be it's start of table name DBSStructureAssistant structureAssistant = DBUtils.getAdapter(DBSStructureAssistant.class, sc); if (structureAssistant != null) { String objectNameMask = nameList.get(0); Collection<DBSObjectReference> tables = structureAssistant.findObjectsByMask( monitor, sc, structureAssistant.getAutoCompleteObjectTypes(), wordDetector.removeQuotes(objectNameMask), wordDetector.isQuoted(objectNameMask), 2); if (!tables.isEmpty()) { return tables.iterator().next().resolveObject(monitor); } } return null; } else { return childObject; } } catch (DBException e) { log.error(e); return null; } }
private void makeStructureProposals( DBRProgressMonitor monitor, DBPDataSource dataSource, List<SQLCompletionProposal> proposals) { final DBSObjectContainer rootContainer = DBUtils.getAdapter(DBSObjectContainer.class, dataSource); if (rootContainer == null) { return; } DBSObjectContainer selectedContainer = null; { DBSObject selectedObject = getSelectedObject(dataSource); if (selectedObject != null) { selectedContainer = DBUtils.getAdapter(DBSObjectContainer.class, selectedObject); } } DBSObjectContainer sc = rootContainer; DBSObject childObject = sc; List<String> tokens = wordDetector.splitWordPart(); String lastToken = null; for (int i = 0; i < tokens.size(); i++) { String token = tokens.get(i); if (i == tokens.size() - 1 && !wordDetector.getWordPart().endsWith(".")) { lastToken = token; break; } if (sc == null) { break; } // Get next structure container try { String objectName = DBObjectNameCaseTransformer.transformName(dataSource, token); childObject = sc.getChild(monitor, objectName); if (childObject == null && i == 0 && selectedContainer != null) { // Probably it is from selected object, let's try it childObject = selectedContainer.getChild(monitor, objectName); if (childObject != null) { sc = selectedContainer; } } if (childObject == null) { if (i == 0) { // Assume it's a table alias ? childObject = this.getTableFromAlias(monitor, sc, token); if (childObject == null) { DBSStructureAssistant structureAssistant = DBUtils.getAdapter(DBSStructureAssistant.class, sc); if (structureAssistant != null) { Collection<DBSObjectReference> references = structureAssistant.findObjectsByMask( monitor, null, structureAssistant.getAutoCompleteObjectTypes(), wordDetector.removeQuotes(token), wordDetector.isQuoted(token), 2); if (!references.isEmpty()) { childObject = references.iterator().next().resolveObject(monitor); } } } } else { // Path element not found. Damn - can't do anything. return; } } if (childObject instanceof DBSObjectContainer) { sc = (DBSObjectContainer) childObject; } else { sc = null; } } catch (DBException e) { log.error(e); return; } } if (childObject == null) { return; } if (lastToken == null) { // Get all children objects as proposals makeProposalsFromChildren(monitor, childObject, null, proposals); } else { // Get matched children makeProposalsFromChildren(monitor, childObject, lastToken, proposals); if (proposals.isEmpty() || tokens.size() == 1) { // At last - try to find child tables by pattern DBSStructureAssistant structureAssistant = null; for (DBSObject object = childObject; object != null; object = object.getParentObject()) { structureAssistant = DBUtils.getAdapter(DBSStructureAssistant.class, object); if (structureAssistant != null) { break; } } if (structureAssistant != null) { makeProposalsFromAssistant(monitor, structureAssistant, sc, lastToken, proposals); } } } }
/** * Extract items using reflect api * * @param monitor progress monitor * @param meta items meta info * @param oldList previous child items * @param toList list ot add new items @return true on success * @return true on success * @throws DBException on any DB error */ private boolean loadTreeItems( DBRProgressMonitor monitor, DBXTreeItem meta, final DBNDatabaseNode[] oldList, final List<DBNDatabaseNode> toList) throws DBException { if (this.isDisposed()) { // Property reading can take really long time so this node can be disposed at this moment - // check it return false; } // Read property using reflection Object valueObject = getValueObject(); if (valueObject == null) { return false; } String propertyName = meta.getPropertyName(); Object propertyValue = extractPropertyValue(monitor, valueObject, propertyName); if (propertyValue == null) { return false; } if (!(propertyValue instanceof Collection<?>)) { log.warn( "Bad property '" + propertyName + "' value: " + propertyValue.getClass().getName()); // $NON-NLS-1$ //$NON-NLS-2$ return false; } DBSObjectFilter filter = getNodeFilter(meta, false); this.filtered = filter != null && !filter.isEmpty(); Collection<?> itemList = (Collection<?>) propertyValue; if (itemList.isEmpty()) { return false; } if (this.isDisposed()) { // Property reading can take really long time so this node can be disposed at this moment - // check it return false; } DBPDataSourceContainer dataSourceContainer = getDataSourceContainer(); boolean showSystem = dataSourceContainer == null || dataSourceContainer.isShowSystemObjects(); for (Object childItem : itemList) { if (childItem == null) { continue; } if (!(childItem instanceof DBSObject)) { log.warn("Bad item type: " + childItem.getClass().getName()); // $NON-NLS-1$ continue; } if (DBUtils.isHiddenObject(childItem)) { // Skip hidden objects continue; } if (!showSystem && childItem instanceof DBPSystemObject && ((DBPSystemObject) childItem).isSystem()) { // Skip system objects continue; } if (filter != null && !filter.matches(((DBSObject) childItem).getName())) { // Doesn't match filter continue; } DBSObject object = (DBSObject) childItem; boolean added = false; if (oldList != null) { // Check that new object is a replacement of old one for (DBNDatabaseNode oldChild : oldList) { if (oldChild.getMeta() == meta && equalObjects(oldChild.getObject(), object)) { oldChild.reloadObject(monitor, object); if (oldChild.allowsChildren() && !oldChild.needsInitialization()) { // Refresh children recursive oldChild.reloadChildren(monitor); } getModel().fireNodeUpdate(this, oldChild, DBNEvent.NodeChange.REFRESH); toList.add(oldChild); added = true; break; } } } if (!added) { // Simply add new item DBNDatabaseItem treeItem = new DBNDatabaseItem(this, meta, object, oldList != null); toList.add(treeItem); } } if (oldList != null) { // Now remove all non-existing items for (DBNDatabaseNode oldChild : oldList) { if (oldChild.getMeta() != meta) { // Wrong type continue; } boolean found = false; for (Object childItem : itemList) { if (childItem instanceof DBSObject && equalObjects(oldChild.getObject(), (DBSObject) childItem)) { found = true; break; } } if (!found) { // Remove old child object oldChild.dispose(true); } } } return true; }