From ca0f07fb9715c52b07ab54aa287b70b0d9363981 Mon Sep 17 00:00:00 2001 From: Eric Bresie Date: Sat, 20 Mar 2021 13:05:44 -0500 Subject: [PATCH 01/16] Allows auto-completion even with no connection and added some basic hints for possible connection issues (i.e. new driver, new connection, connect - showing existing dialog. --- ide/db.sql.editor/nbproject/project.xml | 705 +++++++++--------- .../completion/SQLCompletionProvider.java | 338 ++++++++- .../editor/completion/SQLCompletionQuery.java | 125 +++- .../db/sql/editor/resources/Bundle.properties | 1 + .../modules/db/sql/editor/resources/layer.xml | 9 +- ...s-modules-db-sql-editor_annotation.xml.xml | 34 + 6 files changed, 804 insertions(+), 408 deletions(-) create mode 100644 ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/resources/org-netbeans-modules-db-sql-editor_annotation.xml.xml diff --git a/ide/db.sql.editor/nbproject/project.xml b/ide/db.sql.editor/nbproject/project.xml index 90faa558fdda..d22456274a95 100644 --- a/ide/db.sql.editor/nbproject/project.xml +++ b/ide/db.sql.editor/nbproject/project.xml @@ -1,341 +1,364 @@ - - - - org.netbeans.modules.apisupport.project - - - org.netbeans.modules.db.sql.editor - - - org.netbeans.modules.csl.api - - - - 2 - 2.27 - - - - org.netbeans.modules.csl.types - - - - 1 - 1.0 - - - - org.netbeans.modules.db - - - - 1 - - - - - org.netbeans.modules.db.core - - - - 1.0 - - - - org.netbeans.modules.db.metadata.model - - - - 0-1 - 0.8 - - - - org.netbeans.modules.dbapi - - - - 1.2 - - - - org.netbeans.modules.editor - - - - 3 - 1.53 - - - - org.netbeans.modules.editor.bracesmatching - - - - 0-1 - 1.22 - - - - org.netbeans.modules.editor.completion - - - - 1 - 1.12 - - - - org.netbeans.modules.editor.document - - - - 1.3 - - - - org.netbeans.modules.editor.fold - - - - 1 - 1.42 - - - - org.netbeans.modules.editor.lib - - - - 3 - 4.0 - - - - org.netbeans.modules.editor.lib2 - - - - 1 - 2.0 - - - - org.netbeans.modules.editor.mimelookup - - - - 1 - 1.26 - - - - org.netbeans.modules.lexer - - - - 2 - 1.27 - - - - org.netbeans.modules.projectapi - - - - 1 - 1.26 - - - - org.netbeans.modules.queries - - - - 1 - 1.15 - - - - org.netbeans.swing.plaf - - - - 1.34 - - - - org.openide.actions - - - - 6.2 - - - - org.openide.awt - - - - 6.7 - - - - org.openide.dialogs - - - - 6.2 - - - - org.openide.explorer - - - - 6.8 - - - - org.openide.filesystems - - - - 9.0 - - - - org.openide.loaders - - - - 7.61 - - - - org.openide.modules - - - - 6.2 - - - - org.openide.nodes - - - - 7.23 - - - - org.openide.text - - - - 6.16 - - - - org.openide.util - - - - 9.3 - - - - org.openide.util.lookup - - - - 8.0 - - - - org.openide.util.ui - - - - 9.3 - - - - - - unit - - org.netbeans.libs.junit4 - - - - org.netbeans.modules.csl.api - - - - - - org.netbeans.modules.db - - - - - org.netbeans.modules.db.metadata.model - - - - - org.netbeans.modules.editor.mimelookup - - - - org.netbeans.modules.editor.mimelookup.impl - - - - org.netbeans.modules.lexer - - - - - org.netbeans.modules.nbjunit - - - - - org.netbeans.modules.projectapi.nb - - - org.openide.util.lookup - - - - - - - com.sun.tools.odb - org.netbeans.modules.php.editor - org.netbeans.modules.db.sql.editor.api.completion - - - - + + + + org.netbeans.modules.apisupport.project + + + org.netbeans.modules.db.sql.editor + + + org.netbeans.modules.csl.api + + + + 2 + 2.27 + + + + org.netbeans.modules.csl.types + + + + 1 + 1.0 + + + + org.netbeans.modules.db + + + + 1 + + + + + org.netbeans.modules.db.core + + + + 1.0 + + + + org.netbeans.modules.db.metadata.model + + + + 0-1 + 0.8 + + + + org.netbeans.modules.dbapi + + + + 1.2 + + + + org.netbeans.modules.editor + + + + 3 + 1.53 + + + + org.netbeans.modules.editor.bracesmatching + + + + 0-1 + 1.22 + + + + org.netbeans.modules.editor.completion + + + + 1 + 1.12 + + + + org.netbeans.modules.editor.document + + + + 1.3 + + + + org.netbeans.modules.editor.fold + + + + 1 + 1.42 + + + + org.netbeans.modules.editor.lib + + + + 3 + 4.0 + + + + org.netbeans.modules.editor.lib2 + + + + 1 + 2.0 + + + + org.netbeans.modules.editor.mimelookup + + + + 1 + 1.26 + + + + org.netbeans.modules.lexer + + + + 2 + 1.27 + + + + org.netbeans.modules.projectapi + + + + 1 + 1.26 + + + + org.netbeans.modules.queries + + + + 1 + 1.15 + + + + org.netbeans.spi.editor.hints + + + + 0 + 1.53 + + + + org.netbeans.spi.java.hints + + + + 1.42 + + + + org.netbeans.swing.plaf + + + + 1.34 + + + + org.openide.actions + + + + 6.2 + + + + org.openide.awt + + + + 6.7 + + + + org.openide.dialogs + + + + 6.2 + + + + org.openide.explorer + + + + 6.8 + + + + org.openide.filesystems + + + + 9.0 + + + + org.openide.loaders + + + + 7.61 + + + + org.openide.modules + + + + 6.2 + + + + org.openide.nodes + + + + 7.23 + + + + org.openide.text + + + + 6.16 + + + + org.openide.util + + + + 9.3 + + + + org.openide.util.lookup + + + + 8.0 + + + + org.openide.util.ui + + + + 9.3 + + + + + + unit + + org.netbeans.libs.junit4 + + + + org.netbeans.modules.csl.api + + + + + + org.netbeans.modules.db + + + + + org.netbeans.modules.db.metadata.model + + + + + org.netbeans.modules.editor.mimelookup + + + + org.netbeans.modules.editor.mimelookup.impl + + + + org.netbeans.modules.lexer + + + + + org.netbeans.modules.nbjunit + + + + + org.netbeans.modules.parsing.nb + + + + + + org.netbeans.modules.projectapi.nb + + + org.openide.util.lookup + + + + + + + com.sun.tools.odb + org.netbeans.modules.php.editor + org.netbeans.modules.db.sql.editor.api.completion + + + + diff --git a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionProvider.java b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionProvider.java index 8d3aa3d8a6a9..0dc6667939e3 100644 --- a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionProvider.java +++ b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionProvider.java @@ -19,20 +19,36 @@ package org.netbeans.modules.db.sql.editor.completion; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import javax.swing.text.BadLocationException; import javax.swing.text.Document; import javax.swing.text.JTextComponent; +import org.netbeans.api.db.explorer.ConnectionManager; import org.netbeans.api.db.explorer.DatabaseConnection; -import org.netbeans.api.editor.completion.Completion; +import org.netbeans.api.db.explorer.JDBCDriver; +import org.netbeans.api.db.explorer.JDBCDriverManager; import org.netbeans.api.lexer.Language; import org.netbeans.api.lexer.TokenHierarchy; import org.netbeans.api.lexer.TokenSequence; import org.netbeans.modules.db.api.sql.execute.SQLExecution; import org.netbeans.modules.db.sql.editor.ui.actions.SQLExecutionBaseAction; import org.netbeans.modules.db.sql.lexer.SQLTokenId; +import org.netbeans.modules.editor.NbEditorUtilities; import org.netbeans.spi.editor.completion.CompletionProvider; import org.netbeans.spi.editor.completion.CompletionTask; import org.netbeans.spi.editor.completion.support.AsyncCompletionTask; +import org.netbeans.spi.editor.hints.ChangeInfo; +import org.netbeans.spi.editor.hints.ErrorDescription; +import org.netbeans.spi.editor.hints.ErrorDescriptionFactory; +import org.netbeans.spi.editor.hints.Fix; +import org.netbeans.spi.editor.hints.HintsController; +import org.netbeans.spi.editor.hints.Severity; import org.openide.awt.StatusDisplayer; +import org.openide.text.Annotation; +import org.openide.text.Line; +import org.openide.util.Exceptions; import org.openide.util.Lookup; import org.openide.util.NbBundle; @@ -41,42 +57,190 @@ * @author Andrei Badea */ public class SQLCompletionProvider implements CompletionProvider { + private static final String SQL_CONNECTION_HINT_ID = "sql_connection_hint"; + private String selection; + private static JTextComponent component = null; + private static DatabaseConnection dbconn = null; + @Override public CompletionTask createTask(int queryType, JTextComponent component) { - if (queryType == CompletionProvider.COMPLETION_QUERY_TYPE || queryType == CompletionProvider.COMPLETION_ALL_QUERY_TYPE) { + if (queryType == CompletionProvider.COMPLETION_QUERY_TYPE || + queryType == CompletionProvider.COMPLETION_ALL_QUERY_TYPE) { + + /* to support DB related completion tasks (i.e. auto populating table + names or db columns for given schema) check for connection */ DatabaseConnection dbconn = findDBConn(component); - if (dbconn == null) { - // XXX perhaps should have an item in the completion instead? - Completion.get().hideAll(); - SQLExecutionBaseAction.notifyNoDatabaseConnection(); - return null; + // No database connection set or active + if (SQLCompletionProvider.dbconn == null) { + createSuggestions(component,dbconn); } + return new AsyncCompletionTask(new SQLCompletionQuery(dbconn), component); } + + // not a completion query type so return nothing return null; } + /** + * getAutoQueryTypes is invoked to check whether a popup with suggestions + * should be shown without the user explicitly asking for it. + * + * If either #getAutoQueryTypes return a non-zero value or the user + * explicitly asks for completion, #createTask is invoked with the + * requested type. In case of SQL see + * org.netbeans.modules.db.sql.editor.completion.SQLCompletionQuery. + * + * @param component + * @param typedText + * @return + */ public int getAutoQueryTypes(JTextComponent component, String typedText) { + /* TODO: Need to check "enable/disable" autocomplete is setting. + See NETBEANS-188 */ + + // If "." has not been typed then acceptable to start checking for options. if (!".".equals(typedText)) { // NOI18N return 0; } + // check typed text if dot is present at the selected offset if (!isDotAtOffset(component, component.getSelectionStart() - 1)) { return 0; } + +// List fixes = new ArrayList<>(Collections.emptyList()); +// Document doc = component.getDocument(); +// List warnings = new ArrayList<>(Collections.emptyList()); + + // check if there is a DB connection DatabaseConnection dbconn = findDBConn(component); if (dbconn == null) { String message = NbBundle.getMessage(SQLCompletionProvider.class, "MSG_NoDatabaseConnection"); StatusDisplayer.getDefault().setStatusText(message); - return 0; + /* TODO: Find How to povide tip to create new connection and/or + allow further typing and/or other options. + + Maybe provide a list of available connections. + + return 0; */ +// createSuggestions(component, doc, fixes, warnings, dbconn); + createSuggestions(component, dbconn); } - if (dbconn.getJDBCConnection() == null) { + + // check if DB connection is active + if (dbconn != null && dbconn.getJDBCConnection() == null) { String message = NbBundle.getMessage(SQLCompletionProvider.class, "MSG_NotConnected"); StatusDisplayer.getDefault().setStatusText(message); - return 0; + /* TODO: Find How to povide tip to "allow to connect" and/or + allow further typing and/or other options. */ +// return 0; + + // determine the selected line + selection = component.getSelectedText(); + Document doc = component.getDocument(); + + if (selection.length() > 0) { + component.replaceSelection("" + selection + ""); + // use NbEditorUtilities.getLine() to extract a line from the + // current document and offset, + // for which we need a DocumentListener, as described in the next step: + int lineOffset = component.getSelectionStart() - 1; + + Line myLine = NbEditorUtilities.getLine(doc, lineOffset, false); + + // TODO: Figure out how to set message + //Here we attach our annotation to the line: + SqlConnectionAnnotation.DEFAULT.attach(myLine); + } } return COMPLETION_QUERY_TYPE; } + private void createSuggestions(JTextComponent component, DatabaseConnection dbconn) { + // setup hints and fixes for possible resolution to connection issue + List fixes = new ArrayList<>(Collections.emptyList()); + List warnings = new ArrayList<>(Collections.emptyList()); + + // determine the selected line + selection = component.getSelectedText(); + Document doc = component.getDocument(); + + // for selected lines with content + if (selection != null && selection.length() > 0) { + // bold relevant selected line associated with possible hint/fix + component.replaceSelection("" + selection + ""); + + // use NbEditorUtilities.getLine() to get line from current document and offset, + int lineOffset = component.getSelectionStart() - 1; + int endOffset = lineOffset + selection.length(); + + Line currentLine = NbEditorUtilities.getLine(doc, lineOffset, false); + + // setup sql hints/fixes + try { + // identify possible fixes + + // hint to create a new connection + fixes.add(new SqlNewConnectionFix()); + // hint to add a new driver for connection + fixes.add(new SqlNewDriveFix()); + // hint to correction connection - show dialog to do so + fixes.add(new SqlConnectFix(component)); + + // setup ErrorDescription and add to warnings + warnings.add( + ErrorDescriptionFactory.createErrorDescription( + Severity.WARNING, + "DB Connection Issue", + fixes, + doc, + doc.createPosition(lineOffset), + doc.createPosition(endOffset) + ) + ); + } catch (BadLocationException ex) { + Exceptions.printStackTrace(ex); + } + } else { + // for non-selected lines + + // setup annotations (this may need to be removed in favor of hints/fixes) + + // attach annotation to the line: + Line myLine = NbEditorUtilities.getLine(doc, 0, false); + SqlConnectionAnnotation.DEFAULT.attach(myLine); + + // setup sql hints/fixes + try { + // identify possible fixes + + // hint to create a new connection + fixes.add(new SqlNewConnectionFix()); + // hint to add a new driver for connection + fixes.add(new SqlNewDriveFix()); + // hint to correction connection - show dialog to do so + fixes.add(new SqlConnectFix(component)); + + // no line is selected so add to initial position + // setup ErrorDescription and add to warnings + warnings.add( + ErrorDescriptionFactory.createErrorDescription( + Severity.WARNING, + "DB Connection Issue", + fixes, + doc, + doc.createPosition(0), + doc.createPosition(0) + ) + ); + } catch (BadLocationException ex) { + Exceptions.printStackTrace(ex); + } + HintsController.setErrors(doc, SQL_CONNECTION_HINT_ID, warnings); + } + } + + private static DatabaseConnection findDBConn(JTextComponent component) { Lookup context = findContext(component); if (context == null) { @@ -101,24 +265,35 @@ private static Lookup findContext(JTextComponent component) { return null; } + /** + * For given component object's doc model, determine if given offset + * has applicable dot delimiter token + * @param component + * @param offset + * @return + */ private static boolean isDotAtOffset(JTextComponent component, final int offset) { final Document doc = component.getDocument(); final boolean[] result = { false }; - doc.render(new Runnable() { - public void run() { - TokenSequence seq = getSQLTokenSequence(doc); - if (seq == null) { - return; - } - seq.move(offset); - if (!seq.moveNext() && !seq.movePrevious()) { - return; - } - if (seq.offset() != offset) { - return; - } - result[0] = (seq.token().id() == SQLTokenId.DOT); + // trigger internal model rendering based on SQL tokens + doc.render(() -> { + TokenSequence seq = getSQLTokenSequence(doc); + // no SQL tokens found; done checking + if (seq == null) { + return; + } + // in the sequence move to provided offset location + seq.move(offset); + // no next or previous so done looking for tokens; done checking + if (!seq.moveNext() && !seq.movePrevious()) { + return; + } + // if offset not consistent with sequence offset done checking + if (seq.offset() != offset) { + return; } + // confirm token ID is applicable SQL "dot" token + result[0] = (seq.token().id() == SQLTokenId.DOT); }); return result[0]; } @@ -131,4 +306,119 @@ private static TokenSequence getSQLTokenSequence(Document doc) { TokenHierarchy hierarchy = TokenHierarchy.get(doc); return hierarchy.tokenSequence(SQLTokenId.language()); } + + + /** + * Related to annotation for hints on the left for use during tip context + */ + private static final class SqlConnectionAnnotation extends Annotation { + + static final SqlConnectionAnnotation DEFAULT = new SqlConnectionAnnotation(); + + @Override + public String getAnnotationType() { + return "org-netbeans-modules-db-sql-editor_annotation"; + } + + @Override + public String getShortDescription() { + return "Select Connection to ensure database specific autoompletion"; + } + } + + private static class SqlNewConnectionFix implements Fix { + @Override + public String getText() { + return "Create New Database connection."; + // TODO: Change over to bundle property type to accomidate localization + } + + @Override + public ChangeInfo implement() throws Exception { + + // select given connection + ConnectionManager cm = ConnectionManager.getDefault(); + DatabaseConnection dbconn = findDBConn(component); + + JDBCDriver driver = null; + if (dbconn == null) { + // no connection, have to establish driver and related details + cm.showAddConnectionDialog(null); + } + ChangeInfo results = new ChangeInfo(); + + return results; + } + + private void setupDriver() { + JDBCDriverManager dm = JDBCDriverManager.getDefault(); + JDBCDriver[] drivers = dm.getDrivers(); + + // TODO: Determine how to handle when no drivers are present + if (drivers == null || drivers.length ==0) { + dm.showAddDriverDialog(); + } + } + + public SqlNewConnectionFix() { + } + public SqlNewConnectionFix(DatabaseConnection conn) { + } + } + + /** + * This case handles when driver and connections are available but not connected + */ + private static class SqlConnectFix implements Fix { + + @Override + public String getText() { + return "Connect to database"; + } + + @Override + public ChangeInfo implement() throws Exception { + + SQLExecutionBaseAction.notifyNoDatabaseConnection(); + Document doc = component.getDocument(); + + Line myLine = NbEditorUtilities.getLine(doc, 0, false); + + SqlConnectionAnnotation.DEFAULT.attach(myLine); + ChangeInfo results = new ChangeInfo(); + return results; + } + + public SqlConnectFix(JTextComponent applicableComponent) { + component = applicableComponent; + } + public SqlConnectFix() { + } + } + + /** + * This case handles when driver and connections are available but not connected + */ + private static class SqlNewDriveFix implements Fix { + + @Override + public String getText() { + return "Add a New Database Driver"; + } + + @Override + public ChangeInfo implement() throws Exception { + ConnectionManager cm = ConnectionManager.getDefault(); + JDBCDriverManager dm = JDBCDriverManager.getDefault(); + dm.showAddDriverDialog(); + + ChangeInfo results = new ChangeInfo(); + return results; + } + + public SqlNewDriveFix() { + } + } } + + diff --git a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionQuery.java b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionQuery.java index 57fd2a334696..9d3b257ed252 100644 --- a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionQuery.java +++ b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionQuery.java @@ -120,23 +120,37 @@ public void query(SQLCompletionResultSet resultSet, SQLCompletionEnv newEnv) { private void doQuery(final SQLCompletionEnv newEnv) { try { + // DB Connection available + if (dbconn != null) { + // DB connection present so DBConnMetadataModelManager.get(dbconn).runReadAction(new Action() { @Override public void run(Metadata metadata) { - Connection conn = dbconn.getJDBCConnection(); - if (conn == null) { - return; - } + Connection conn = null; + if (dbconn != null) { + conn = dbconn.getJDBCConnection(); + } Quoter quoter = null; try { - DatabaseMetaData dmd = conn.getMetaData(); - quoter = SQLIdentifiers.createQuoter(dmd); + if (conn != null) { + // get Database meta data + DatabaseMetaData dmd = conn.getMetaData(); + quoter = SQLIdentifiers.createQuoter(dmd); + } } catch (SQLException e) { throw new MetadataException(e); } - doQuery(newEnv, metadata, quoter); + if (quoter != null) { + doQuery(newEnv, metadata, quoter); + } else { + return; + } } }); + } else { + // No DB Connection established presently + doQuery(newEnv, metadata, quoter); + } } catch (MetadataModelException e) { reportError(e); } @@ -149,30 +163,46 @@ SQLCompletionItems doQuery(SQLCompletionEnv env, Metadata metadata, Quoter quote this.quoter = quoter; anchorOffset = -1; substitutionOffset = 0; + + // address empty env so add basic keywords items = new SQLCompletionItems(quoter, env.getSubstitutionHandler()); + if (env.getTokenSequence().isEmpty()) { completeKeyword("SELECT", "INSERT", "DELETE", "DROP", "UPDATE", "CREATE"); //NOI18N return items; } + + // not empty so address possible statement cases + if (quoter == null) {} statement = SQLStatementAnalyzer.analyze(env.getTokenSequence(), quoter); + + // unable to find relevant case so include basic keywords items if (statement == null) { completeKeyword("SELECT", "INSERT", "DELETE", "DROP", "UPDATE", "CREATE"); //NOI18N return items; } + + // found a create case so update to include create case items if (statement.getKind() == SQLStatementKind.CREATE && ((CreateStatement) statement).hasBody()) { completeCreateBody(); return items; } + + // checking context of offset to see if applicable; if not then set to basics context = statement.getContextAtOffset(env.getCaretOffset()); if (context == null) { completeKeyword("SELECT", "INSERT", "DELETE", "DROP", "UPDATE", "CREATE"); //NOI18N return items; } + + // from context look for identifiers; if none then return current context ident = findIdentifier(); if (ident == null) { completeKeyword(context); return items; } + + // from ident anchorif identifier identified then determine kin anchorOffset = ident.anchorOffset; substitutionOffset = ident.substitutionOffset; SQLStatementKind kind = statement.getKind(); @@ -474,36 +504,40 @@ private void completeColumnWithDefinedTuple(Identifier ident) { } } - /** Adds columns, tuples, schemas and catalogs according to given identifier. */ + /** + * Adds columns, tuples, schema and catalogs according to given identifier. + */ private void completeColumnSimpleIdent(String typedPrefix, boolean quoted) { if (tablesClause != null && !(tablesClause.getUnaliasedTableNames().isEmpty() && tablesClause.getAliasedTableNames().isEmpty())) { completeSimpleIdentBasedOnFromClause(typedPrefix, quoted); } else { - Schema defaultSchema = metadata.getDefaultSchema(); - if (defaultSchema != null) { - // All columns in default schema, but only if a prefix has been typed, otherwise there - // would be too many columns. - if (typedPrefix != null) { - for (Table table : defaultSchema.getTables()) { - items.addColumns(table, typedPrefix, quoted, substitutionOffset); + if (metadata != null) { + Schema defaultSchema = metadata.getDefaultSchema(); + if (defaultSchema != null) { + // All columns in default schema, but only if a prefix has been typed, otherwise there + // would be too many columns. + if (typedPrefix != null) { + for (Table table : defaultSchema.getTables()) { + items.addColumns(table, typedPrefix, quoted, substitutionOffset); + } + if (includeViews) { + for (View view : defaultSchema.getViews()) { + items.addColumns(view, typedPrefix, quoted, substitutionOffset); + } + } } + // All tuples in default schema. + items.addTables(defaultSchema, null, typedPrefix, quoted, substitutionOffset); if (includeViews) { - for (View view : defaultSchema.getViews()) { - items.addColumns(view, typedPrefix, quoted, substitutionOffset); - } + items.addViews(defaultSchema, null, typedPrefix, quoted, substitutionOffset); } } - // All tuples in default schema. - items.addTables(defaultSchema, null, typedPrefix, quoted, substitutionOffset); - if (includeViews) { - items.addViews(defaultSchema, null, typedPrefix, quoted, substitutionOffset); - } + // All schemas. + Catalog defaultCatalog = metadata.getDefaultCatalog(); + items.addSchemas(defaultCatalog, null, typedPrefix, quoted, substitutionOffset); + // All catalogs. + items.addCatalogs(metadata, null, typedPrefix, quoted, substitutionOffset); } - // All schemas. - Catalog defaultCatalog = metadata.getDefaultCatalog(); - items.addSchemas(defaultCatalog, null, typedPrefix, quoted, substitutionOffset); - // All catalogs. - items.addCatalogs(metadata, null, typedPrefix, quoted, substitutionOffset); } } @@ -587,19 +621,22 @@ private void completeColumnQualIdent(QualIdent fullyTypedIdent, String lastPrefi /** Adds all tuples from default schema, all schemas from defaultcatalog * and all catalogs. */ private void completeTupleSimpleIdent(String typedPrefix, boolean quoted) { - Schema defaultSchema = metadata.getDefaultSchema(); - if (defaultSchema != null) { - // All tuples in default schema. - items.addTables(defaultSchema, null, typedPrefix, quoted, substitutionOffset); - if (includeViews) { - items.addViews(defaultSchema, null, typedPrefix, quoted, substitutionOffset); + // connection metadata available so add to available items + if (metadata != null ){ + Schema defaultSchema = metadata.getDefaultSchema(); + if (defaultSchema != null) { + // All tuples in default schema. + items.addTables(defaultSchema, null, typedPrefix, quoted, substitutionOffset); + if (includeViews) { + items.addViews(defaultSchema, null, typedPrefix, quoted, substitutionOffset); + } } + // All schemas. + Catalog defaultCatalog = metadata.getDefaultCatalog(); + items.addSchemas(defaultCatalog, null, typedPrefix, quoted, substitutionOffset); + // All catalogs. + items.addCatalogs(metadata, null, typedPrefix, quoted, substitutionOffset); } - // All schemas. - Catalog defaultCatalog = metadata.getDefaultCatalog(); - items.addSchemas(defaultCatalog, null, typedPrefix, quoted, substitutionOffset); - // All catalogs. - items.addCatalogs(metadata, null, typedPrefix, quoted, substitutionOffset); } /** Adds all tuples in schema get from fully qualified identifier or all @@ -744,13 +781,16 @@ private void completeCatalog(Catalog catalog, String prefix, boolean quoted) { } private Catalog resolveCatalog(QualIdent catalogName) { - if (catalogName.isSimple()) { + if (metadata != null && catalogName.isSimple()) { return metadata.getCatalog(catalogName.getSimpleName()); } return null; } private Schema resolveSchema(QualIdent schemaName) { + if (metadata == null) { + return null; + } Schema schema = null; switch (schemaName.size()) { case 1: @@ -768,7 +808,7 @@ private Schema resolveSchema(QualIdent schemaName) { } private Tuple resolveTuple(QualIdent tupleName) { - if (tupleName == null) { + if (tupleName == null || metadata == null) { return null; } Tuple tuple = null; @@ -993,6 +1033,9 @@ private Identifier createIdentifier(List parts, boolean incomplete, int } // Fine, nothing was typed. } else { + if (quoter == null) { + return null; + } if (!incomplete) { lastPrefix = parts.remove(parts.size() - 1); String quoteString = quoter.getQuoteString(); diff --git a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/resources/Bundle.properties b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/resources/Bundle.properties index 87ec6b6d14ba..3815692f9a89 100644 --- a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/resources/Bundle.properties +++ b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/resources/Bundle.properties @@ -41,3 +41,4 @@ sql-keyword=Keyword sql-errors=Error sql-dot=Period +LAB_db_sql_editor_annotation_warn="Select Connection from the combo box at the top of the SQL Editor window." diff --git a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/resources/layer.xml b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/resources/layer.xml index d989aafb01aa..ed263fcfb910 100644 --- a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/resources/layer.xml +++ b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/resources/layer.xml @@ -58,7 +58,7 @@ - + @@ -110,7 +110,7 @@ - + @@ -148,6 +148,11 @@ + + + + diff --git a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/resources/org-netbeans-modules-db-sql-editor_annotation.xml.xml b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/resources/org-netbeans-modules-db-sql-editor_annotation.xml.xml new file mode 100644 index 000000000000..cfa3cffe6883 --- /dev/null +++ b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/resources/org-netbeans-modules-db-sql-editor_annotation.xml.xml @@ -0,0 +1,34 @@ + + + + \ No newline at end of file From e6d40701ae1e7e88e55ae41fdfdde001ef3024ac Mon Sep 17 00:00:00 2001 From: Eric Bresie Date: Sat, 20 Mar 2021 13:06:26 -0500 Subject: [PATCH 02/16] Allows auto-completion even with no connection and added some basic hints for possible connection issues (i.e. new driver, new connection, connect - showing existing dialog. --- .../netbeans/modules/db/sql/analyzer/SQLStatementAnalyzer.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/analyzer/SQLStatementAnalyzer.java b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/analyzer/SQLStatementAnalyzer.java index 299e2a39140e..1b132e43483c 100644 --- a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/analyzer/SQLStatementAnalyzer.java +++ b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/analyzer/SQLStatementAnalyzer.java @@ -239,6 +239,8 @@ protected QualIdent parseIdentifier() { } protected String getUnquotedIdentifier() { + if (quoter == null) + return ""; return quoter.unquote(seq.token().text().toString()); } From 96b4f70634bdfc1931044213d4a4b18221131867 Mon Sep 17 00:00:00 2001 From: Eric Bresie Date: Sat, 3 Apr 2021 10:26:25 -0500 Subject: [PATCH 03/16] Updates based on PR comments. Removed "annotation" and related items associated with them. --- .../db/sql/analyzer/SQLStatementAnalyzer.java | 5 +- .../completion/SQLCompletionProvider.java | 82 +---------- .../editor/completion/SQLCompletionQuery.java | 134 ++++++++++-------- ...s-modules-db-sql-editor_annotation.xml.xml | 34 ----- 4 files changed, 82 insertions(+), 173 deletions(-) delete mode 100644 ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/resources/org-netbeans-modules-db-sql-editor_annotation.xml.xml diff --git a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/analyzer/SQLStatementAnalyzer.java b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/analyzer/SQLStatementAnalyzer.java index 1b132e43483c..4c17d2041285 100644 --- a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/analyzer/SQLStatementAnalyzer.java +++ b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/analyzer/SQLStatementAnalyzer.java @@ -34,7 +34,6 @@ import org.netbeans.modules.db.sql.analyzer.SQLStatement.Context; import org.netbeans.modules.db.sql.editor.StringUtils; import org.netbeans.modules.db.sql.lexer.SQLTokenId; - /** * * @author Jiri Rechtacek, Jiri Skrivanek @@ -239,8 +238,10 @@ protected QualIdent parseIdentifier() { } protected String getUnquotedIdentifier() { - if (quoter == null) + // when quoter unavailable likely due to lack of connection + if (quoter == null) { return ""; + } return quoter.unquote(seq.token().text().toString()); } diff --git a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionProvider.java b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionProvider.java index 0dc6667939e3..3b47b1cf4fe0 100644 --- a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionProvider.java +++ b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionProvider.java @@ -46,7 +46,6 @@ import org.netbeans.spi.editor.hints.HintsController; import org.netbeans.spi.editor.hints.Severity; import org.openide.awt.StatusDisplayer; -import org.openide.text.Annotation; import org.openide.text.Line; import org.openide.util.Exceptions; import org.openide.util.Lookup; @@ -58,7 +57,6 @@ */ public class SQLCompletionProvider implements CompletionProvider { private static final String SQL_CONNECTION_HINT_ID = "sql_connection_hint"; - private String selection; private static JTextComponent component = null; private static DatabaseConnection dbconn = null; @@ -96,8 +94,7 @@ public CompletionTask createTask(int queryType, JTextComponent component) { * @return */ public int getAutoQueryTypes(JTextComponent component, String typedText) { - /* TODO: Need to check "enable/disable" autocomplete is setting. - See NETBEANS-188 */ + // XXX: Check if "enable/disable" autocomplete is setting. See NETBEANS-188 // If "." has not been typed then acceptable to start checking for options. if (!".".equals(typedText)) { // NOI18N @@ -108,50 +105,21 @@ public int getAutoQueryTypes(JTextComponent component, String typedText) { return 0; } -// List fixes = new ArrayList<>(Collections.emptyList()); -// Document doc = component.getDocument(); -// List warnings = new ArrayList<>(Collections.emptyList()); - // check if there is a DB connection DatabaseConnection dbconn = findDBConn(component); if (dbconn == null) { String message = NbBundle.getMessage(SQLCompletionProvider.class, "MSG_NoDatabaseConnection"); StatusDisplayer.getDefault().setStatusText(message); - /* TODO: Find How to povide tip to create new connection and/or - allow further typing and/or other options. - - Maybe provide a list of available connections. - - return 0; */ -// createSuggestions(component, doc, fixes, warnings, dbconn); createSuggestions(component, dbconn); + SQLExecutionBaseAction.notifyNoDatabaseConnection(); } // check if DB connection is active if (dbconn != null && dbconn.getJDBCConnection() == null) { String message = NbBundle.getMessage(SQLCompletionProvider.class, "MSG_NotConnected"); StatusDisplayer.getDefault().setStatusText(message); - /* TODO: Find How to povide tip to "allow to connect" and/or - allow further typing and/or other options. */ -// return 0; - - // determine the selected line - selection = component.getSelectedText(); - Document doc = component.getDocument(); - - if (selection.length() > 0) { - component.replaceSelection("" + selection + ""); - // use NbEditorUtilities.getLine() to extract a line from the - // current document and offset, - // for which we need a DocumentListener, as described in the next step: - int lineOffset = component.getSelectionStart() - 1; - - Line myLine = NbEditorUtilities.getLine(doc, lineOffset, false); - - // TODO: Figure out how to set message - //Here we attach our annotation to the line: - SqlConnectionAnnotation.DEFAULT.attach(myLine); - } + SQLExecutionBaseAction.notifyNoDatabaseConnection(); + // XXX: Maybe add content specific "fixs" } return COMPLETION_QUERY_TYPE; } @@ -162,14 +130,11 @@ private void createSuggestions(JTextComponent component, DatabaseConnection dbco List warnings = new ArrayList<>(Collections.emptyList()); // determine the selected line - selection = component.getSelectedText(); - Document doc = component.getDocument(); + String selection = component.getSelectedText(); + Document doc = component.getDocument(); // for selected lines with content if (selection != null && selection.length() > 0) { - // bold relevant selected line associated with possible hint/fix - component.replaceSelection("" + selection + ""); - // use NbEditorUtilities.getLine() to get line from current document and offset, int lineOffset = component.getSelectionStart() - 1; int endOffset = lineOffset + selection.length(); @@ -203,13 +168,7 @@ private void createSuggestions(JTextComponent component, DatabaseConnection dbco } } else { // for non-selected lines - - // setup annotations (this may need to be removed in favor of hints/fixes) - - // attach annotation to the line: - Line myLine = NbEditorUtilities.getLine(doc, 0, false); - SqlConnectionAnnotation.DEFAULT.attach(myLine); - + // setup sql hints/fixes try { // identify possible fixes @@ -239,7 +198,6 @@ private void createSuggestions(JTextComponent component, DatabaseConnection dbco HintsController.setErrors(doc, SQL_CONNECTION_HINT_ID, warnings); } } - private static DatabaseConnection findDBConn(JTextComponent component) { Lookup context = findContext(component); @@ -306,31 +264,11 @@ private static TokenSequence getSQLTokenSequence(Document doc) { TokenHierarchy hierarchy = TokenHierarchy.get(doc); return hierarchy.tokenSequence(SQLTokenId.language()); } - - /** - * Related to annotation for hints on the left for use during tip context - */ - private static final class SqlConnectionAnnotation extends Annotation { - - static final SqlConnectionAnnotation DEFAULT = new SqlConnectionAnnotation(); - - @Override - public String getAnnotationType() { - return "org-netbeans-modules-db-sql-editor_annotation"; - } - - @Override - public String getShortDescription() { - return "Select Connection to ensure database specific autoompletion"; - } - } - private static class SqlNewConnectionFix implements Fix { @Override public String getText() { return "Create New Database connection."; - // TODO: Change over to bundle property type to accomidate localization } @Override @@ -354,7 +292,6 @@ private void setupDriver() { JDBCDriverManager dm = JDBCDriverManager.getDefault(); JDBCDriver[] drivers = dm.getDrivers(); - // TODO: Determine how to handle when no drivers are present if (drivers == null || drivers.length ==0) { dm.showAddDriverDialog(); } @@ -380,11 +317,6 @@ public String getText() { public ChangeInfo implement() throws Exception { SQLExecutionBaseAction.notifyNoDatabaseConnection(); - Document doc = component.getDocument(); - - Line myLine = NbEditorUtilities.getLine(doc, 0, false); - - SqlConnectionAnnotation.DEFAULT.attach(myLine); ChangeInfo results = new ChangeInfo(); return results; } diff --git a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionQuery.java b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionQuery.java index 9d3b257ed252..54548cb7d63e 100644 --- a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionQuery.java +++ b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionQuery.java @@ -122,31 +122,36 @@ private void doQuery(final SQLCompletionEnv newEnv) { try { // DB Connection available if (dbconn != null) { - // DB connection present so - DBConnMetadataModelManager.get(dbconn).runReadAction(new Action() { - @Override - public void run(Metadata metadata) { - Connection conn = null; - if (dbconn != null) { - conn = dbconn.getJDBCConnection(); - } - Quoter quoter = null; - try { - if (conn != null) { - // get Database meta data - DatabaseMetaData dmd = conn.getMetaData(); - quoter = SQLIdentifiers.createQuoter(dmd); + // DB connection present so + DBConnMetadataModelManager.get(dbconn).runReadAction(new Action() { + @Override + public void run(Metadata metadata) { + Connection conn = null; + if (dbconn != null) { + conn = dbconn.getJDBCConnection(); + } + Quoter quoter = null; + try { + /* if connection available allow for bb meta data + and quoter to help in auto completion */ + if (conn != null) { + // get Database meta data + DatabaseMetaData dmd = conn.getMetaData(); + quoter = SQLIdentifiers.createQuoter(dmd); + } + } catch (SQLException e) { + throw new MetadataException(e); + } + /* if quoter available then allow for query for + auto completion to occur, else avoid this sort of + activities when quoter/connection not available*/ + if (quoter != null) { + doQuery(newEnv, metadata, quoter); + } else { + return; } - } catch (SQLException e) { - throw new MetadataException(e); - } - if (quoter != null) { - doQuery(newEnv, metadata, quoter); - } else { - return; } - } - }); + }); } else { // No DB Connection established presently doQuery(newEnv, metadata, quoter); @@ -173,8 +178,7 @@ SQLCompletionItems doQuery(SQLCompletionEnv env, Metadata metadata, Quoter quote } // not empty so address possible statement cases - if (quoter == null) {} - statement = SQLStatementAnalyzer.analyze(env.getTokenSequence(), quoter); + statement = SQLStatementAnalyzer.analyze(env.getTokenSequence(), quoter); // unable to find relevant case so include basic keywords items if (statement == null) { @@ -542,6 +546,7 @@ private void completeColumnSimpleIdent(String typedPrefix, boolean quoted) { } private void completeColumnWithTupleIfSimpleIdent(String typedPrefix, boolean quoted) { + if (metadata != null) { Schema defaultSchema = metadata.getDefaultSchema(); if (defaultSchema != null) { // All columns in default schema, but only if a prefix has been typed, otherwise there @@ -568,6 +573,7 @@ private void completeColumnWithTupleIfSimpleIdent(String typedPrefix, boolean qu items.addSchemas(defaultCatalog, null, typedPrefix, quoted, substitutionOffset); // All catalogs. items.addCatalogs(metadata, null, typedPrefix, quoted, substitutionOffset); + } } private void completeColumnWithTupleIfQualIdent(QualIdent fullyTypedIdent, String lastPrefix, boolean quoted) { @@ -680,6 +686,7 @@ private void completeSimpleIdentBasedOnFromClause(String typedPrefix, boolean qu items.addColumns(tuple, typedPrefix, quoted, substitutionOffset); } // Tuples from default schema, restricted to non-aliased tuple names in the FROM clause. + if (metadata != null ) { Schema defaultSchema = metadata.getDefaultSchema(); if (defaultSchema != null) { Set simpleTupleNames = new TreeSet(); @@ -711,6 +718,7 @@ private void completeSimpleIdentBasedOnFromClause(String typedPrefix, boolean qu Catalog defaultCatalog = metadata.getDefaultCatalog(); items.addSchemas(defaultCatalog, schemaNames, typedPrefix, quoted, substitutionOffset); items.addCatalogs(metadata, catalogNames, typedPrefix, quoted, substitutionOffset); + } } private void completeQualIdentBasedOnFromClause(QualIdent fullyTypedIdent, String lastPrefix, boolean quoted) { @@ -788,21 +796,20 @@ private Catalog resolveCatalog(QualIdent catalogName) { } private Schema resolveSchema(QualIdent schemaName) { - if (metadata == null) { - return null; - } Schema schema = null; - switch (schemaName.size()) { - case 1: - Catalog catalog = metadata.getDefaultCatalog(); - schema = catalog.getSchema(schemaName.getSimpleName()); - break; - case 2: - catalog = metadata.getCatalog(schemaName.getFirstQualifier()); - if (catalog != null) { + if (metadata != null) { + switch (schemaName.size()) { + case 1: + Catalog catalog = metadata.getDefaultCatalog(); schema = catalog.getSchema(schemaName.getSimpleName()); - } - break; + break; + case 2: + catalog = metadata.getCatalog(schemaName.getFirstQualifier()); + if (catalog != null) { + schema = catalog.getSchema(schemaName.getSimpleName()); + } + break; + } } return schema; } @@ -958,7 +965,7 @@ private Identifier findIdentifier() { String part; int offset = caretOffset - seq.offset(); String tokenText = seq.token().text().toString(); - if (offset > 0 && offset < seq.token().length()) { + if (offset > 0 && offset < seq.token().length() && quoter != null) { String quoteString = quoter.getQuoteString(); if (tokenText.startsWith(quoteString) && tokenText.endsWith(quoteString) && offset == tokenText.length() - 1) { // identifier inside closed quotes and cursor before ending quote ("foo|") @@ -1018,6 +1025,10 @@ private Identifier findIdentifier() { } /** + * Used to create an Identifier based on current parts of the expression so far, + * if the details are "Complete" and the offset of given prefix involved. + * + * @param parts the list of potentail * @param lastPrefixOffset the offset of the last prefix in the identifier, or * if no such prefix, the caret offset. * @return @@ -1033,33 +1044,32 @@ private Identifier createIdentifier(List parts, boolean incomplete, int } // Fine, nothing was typed. } else { - if (quoter == null) { - return null; - } - if (!incomplete) { - lastPrefix = parts.remove(parts.size() - 1); - String quoteString = quoter.getQuoteString(); - if (quoteString.length() > 0 && lastPrefix.startsWith(quoteString)) { - if (lastPrefix.endsWith(quoteString) && lastPrefix.length() > quoteString.length()) { - // User typed '"foo"."bar"|', can't complete that. + if (quoter != null ) { + if (!incomplete) { + lastPrefix = parts.remove(parts.size() - 1); + String quoteString = quoter.getQuoteString(); + if (quoteString.length() > 0 && lastPrefix.startsWith(quoteString)) { + if (lastPrefix.endsWith(quoteString) && lastPrefix.length() > quoteString.length()) { + // User typed '"foo"."bar"|', can't complete that. + return null; + } + int lastPrefixLength = lastPrefix.length(); + lastPrefix = quoter.unquote(lastPrefix); + lastPrefixOffset = lastPrefixOffset + (lastPrefixLength - lastPrefix.length()); + quoted = true; + } else if (quoteString.length() > 0 && lastPrefix.endsWith(quoteString)) { + // User typed '"foo".bar"|', can't complete. return null; } - int lastPrefixLength = lastPrefix.length(); - lastPrefix = quoter.unquote(lastPrefix); - lastPrefixOffset = lastPrefixOffset + (lastPrefixLength - lastPrefix.length()); - quoted = true; - } else if (quoteString.length() > 0 && lastPrefix.endsWith(quoteString)) { - // User typed '"foo".bar"|', can't complete. - return null; } - } - for (int i = 0; i < parts.size(); i++) { - String unquoted = quoter.unquote(parts.get(i)); - if (unquoted.length() == 0) { - // User typed something like '"foo".""."bar|'. - return null; + for (int i = 0; i < parts.size(); i++) { + String unquoted = quoter.unquote(parts.get(i)); + if (unquoted.length() == 0) { + // User typed something like '"foo".""."bar|'. + return null; + } + parts.set(i, unquoted); } - parts.set(i, unquoted); } } return new Identifier(new QualIdent(parts), lastPrefix, quoted, lastPrefixOffset, substOffset); diff --git a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/resources/org-netbeans-modules-db-sql-editor_annotation.xml.xml b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/resources/org-netbeans-modules-db-sql-editor_annotation.xml.xml deleted file mode 100644 index cfa3cffe6883..000000000000 --- a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/resources/org-netbeans-modules-db-sql-editor_annotation.xml.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - \ No newline at end of file From 8935abac6442890cf11c610559e5da90edb8b4c4 Mon Sep 17 00:00:00 2001 From: Eric Bresie Date: Sat, 3 Apr 2021 11:30:48 -0500 Subject: [PATCH 04/16] Removed reference to netbeans-modules-db-sql-editor_annotation.xml which is no longer used. --- .../org/netbeans/modules/db/sql/editor/resources/layer.xml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/resources/layer.xml b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/resources/layer.xml index ed263fcfb910..7257cdcdf705 100644 --- a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/resources/layer.xml +++ b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/resources/layer.xml @@ -148,11 +148,6 @@ - - - - From 7755bda28db6969ea47e619241471c06a8444f2a Mon Sep 17 00:00:00 2001 From: Eric Bresie Date: Mon, 5 Apr 2021 07:46:23 -0500 Subject: [PATCH 05/16] Removed reference to spi.java.hints from project.xml file which is not needed. --- ide/db.sql.editor/nbproject/project.xml | 720 ++++++++++++------------ 1 file changed, 356 insertions(+), 364 deletions(-) diff --git a/ide/db.sql.editor/nbproject/project.xml b/ide/db.sql.editor/nbproject/project.xml index d22456274a95..68f7a346e4ea 100644 --- a/ide/db.sql.editor/nbproject/project.xml +++ b/ide/db.sql.editor/nbproject/project.xml @@ -1,364 +1,356 @@ - - - - org.netbeans.modules.apisupport.project - - - org.netbeans.modules.db.sql.editor - - - org.netbeans.modules.csl.api - - - - 2 - 2.27 - - - - org.netbeans.modules.csl.types - - - - 1 - 1.0 - - - - org.netbeans.modules.db - - - - 1 - - - - - org.netbeans.modules.db.core - - - - 1.0 - - - - org.netbeans.modules.db.metadata.model - - - - 0-1 - 0.8 - - - - org.netbeans.modules.dbapi - - - - 1.2 - - - - org.netbeans.modules.editor - - - - 3 - 1.53 - - - - org.netbeans.modules.editor.bracesmatching - - - - 0-1 - 1.22 - - - - org.netbeans.modules.editor.completion - - - - 1 - 1.12 - - - - org.netbeans.modules.editor.document - - - - 1.3 - - - - org.netbeans.modules.editor.fold - - - - 1 - 1.42 - - - - org.netbeans.modules.editor.lib - - - - 3 - 4.0 - - - - org.netbeans.modules.editor.lib2 - - - - 1 - 2.0 - - - - org.netbeans.modules.editor.mimelookup - - - - 1 - 1.26 - - - - org.netbeans.modules.lexer - - - - 2 - 1.27 - - - - org.netbeans.modules.projectapi - - - - 1 - 1.26 - - - - org.netbeans.modules.queries - - - - 1 - 1.15 - - - - org.netbeans.spi.editor.hints - - - - 0 - 1.53 - - - - org.netbeans.spi.java.hints - - - - 1.42 - - - - org.netbeans.swing.plaf - - - - 1.34 - - - - org.openide.actions - - - - 6.2 - - - - org.openide.awt - - - - 6.7 - - - - org.openide.dialogs - - - - 6.2 - - - - org.openide.explorer - - - - 6.8 - - - - org.openide.filesystems - - - - 9.0 - - - - org.openide.loaders - - - - 7.61 - - - - org.openide.modules - - - - 6.2 - - - - org.openide.nodes - - - - 7.23 - - - - org.openide.text - - - - 6.16 - - - - org.openide.util - - - - 9.3 - - - - org.openide.util.lookup - - - - 8.0 - - - - org.openide.util.ui - - - - 9.3 - - - - - - unit - - org.netbeans.libs.junit4 - - - - org.netbeans.modules.csl.api - - - - - - org.netbeans.modules.db - - - - - org.netbeans.modules.db.metadata.model - - - - - org.netbeans.modules.editor.mimelookup - - - - org.netbeans.modules.editor.mimelookup.impl - - - - org.netbeans.modules.lexer - - - - - org.netbeans.modules.nbjunit - - - - - org.netbeans.modules.parsing.nb - - - - - - org.netbeans.modules.projectapi.nb - - - org.openide.util.lookup - - - - - - - com.sun.tools.odb - org.netbeans.modules.php.editor - org.netbeans.modules.db.sql.editor.api.completion - - - - + + + + org.netbeans.modules.apisupport.project + + + org.netbeans.modules.db.sql.editor + + + org.netbeans.modules.csl.api + + + + 2 + 2.27 + + + + org.netbeans.modules.csl.types + + + + 1 + 1.0 + + + + org.netbeans.modules.db + + + + 1 + + + + + org.netbeans.modules.db.core + + + + 1.0 + + + + org.netbeans.modules.db.metadata.model + + + + 0-1 + 0.8 + + + + org.netbeans.modules.dbapi + + + + 1.2 + + + + org.netbeans.modules.editor + + + + 3 + 1.53 + + + + org.netbeans.modules.editor.bracesmatching + + + + 0-1 + 1.22 + + + + org.netbeans.modules.editor.completion + + + + 1 + 1.12 + + + + org.netbeans.modules.editor.document + + + + 1.3 + + + + org.netbeans.modules.editor.fold + + + + 1 + 1.42 + + + + org.netbeans.modules.editor.lib + + + + 3 + 4.0 + + + + org.netbeans.modules.editor.lib2 + + + + 1 + 2.0 + + + + org.netbeans.modules.editor.mimelookup + + + + 1 + 1.26 + + + + org.netbeans.modules.lexer + + + + 2 + 1.27 + + + + org.netbeans.modules.projectapi + + + + 1 + 1.26 + + + + org.netbeans.modules.queries + + + + 1 + 1.15 + + + + org.netbeans.spi.editor.hints + + + + 0 + 1.53 + + + + org.netbeans.swing.plaf + + + + 1.34 + + + + org.openide.actions + + + + 6.2 + + + + org.openide.awt + + + + 6.7 + + + + org.openide.dialogs + + + + 6.2 + + + + org.openide.explorer + + + + 6.8 + + + + org.openide.filesystems + + + + 9.0 + + + + org.openide.loaders + + + + 7.61 + + + + org.openide.modules + + + + 6.2 + + + + org.openide.nodes + + + + 7.23 + + + + org.openide.text + + + + 6.16 + + + + org.openide.util + + + + 9.3 + + + + org.openide.util.lookup + + + + 8.0 + + + + org.openide.util.ui + + + + 9.3 + + + + + + unit + + org.netbeans.libs.junit4 + + + + org.netbeans.modules.csl.api + + + + + + org.netbeans.modules.db + + + + + org.netbeans.modules.db.metadata.model + + + + + org.netbeans.modules.editor.mimelookup + + + + org.netbeans.modules.editor.mimelookup.impl + + + + org.netbeans.modules.lexer + + + + + org.netbeans.modules.nbjunit + + + + + org.netbeans.modules.parsing.nb + + + + + + org.netbeans.modules.projectapi.nb + + + org.openide.util.lookup + + + + + + + com.sun.tools.odb + org.netbeans.modules.php.editor + org.netbeans.modules.db.sql.editor.api.completion + + + + From 9fb0a8c5d8ff601903d15f6d4f5712e0c67eee15 Mon Sep 17 00:00:00 2001 From: Eric Bresie Date: Fri, 9 Apr 2021 11:08:28 -0500 Subject: [PATCH 06/16] Removed unused LAB_db_sql_editor_annotation which is not needed --- .../netbeans/modules/db/sql/editor/resources/Bundle.properties | 2 -- 1 file changed, 2 deletions(-) diff --git a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/resources/Bundle.properties b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/resources/Bundle.properties index 3815692f9a89..e9f4f33c5d62 100644 --- a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/resources/Bundle.properties +++ b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/resources/Bundle.properties @@ -40,5 +40,3 @@ sql-double-literal=Floating Point sql-keyword=Keyword sql-errors=Error sql-dot=Period - -LAB_db_sql_editor_annotation_warn="Select Connection from the combo box at the top of the SQL Editor window." From b2ba9a852ddd3ec301b395cf403cdbe589e9f61a Mon Sep 17 00:00:00 2001 From: Eric Bresie Date: Fri, 9 Apr 2021 11:09:08 -0500 Subject: [PATCH 07/16] Removed fix/hints and related updates. --- .../completion/SQLCompletionProvider.java | 169 +----------------- 1 file changed, 1 insertion(+), 168 deletions(-) diff --git a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionProvider.java b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionProvider.java index 3b47b1cf4fe0..e1f98dd32da8 100644 --- a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionProvider.java +++ b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionProvider.java @@ -68,10 +68,6 @@ public CompletionTask createTask(int queryType, JTextComponent component) { /* to support DB related completion tasks (i.e. auto populating table names or db columns for given schema) check for connection */ DatabaseConnection dbconn = findDBConn(component); - // No database connection set or active - if (SQLCompletionProvider.dbconn == null) { - createSuggestions(component,dbconn); - } return new AsyncCompletionTask(new SQLCompletionQuery(dbconn), component); } @@ -95,7 +91,7 @@ public CompletionTask createTask(int queryType, JTextComponent component) { */ public int getAutoQueryTypes(JTextComponent component, String typedText) { // XXX: Check if "enable/disable" autocomplete is setting. See NETBEANS-188 - + // If "." has not been typed then acceptable to start checking for options. if (!".".equals(typedText)) { // NOI18N return 0; @@ -110,7 +106,6 @@ public int getAutoQueryTypes(JTextComponent component, String typedText) { if (dbconn == null) { String message = NbBundle.getMessage(SQLCompletionProvider.class, "MSG_NoDatabaseConnection"); StatusDisplayer.getDefault().setStatusText(message); - createSuggestions(component, dbconn); SQLExecutionBaseAction.notifyNoDatabaseConnection(); } @@ -124,81 +119,6 @@ public int getAutoQueryTypes(JTextComponent component, String typedText) { return COMPLETION_QUERY_TYPE; } - private void createSuggestions(JTextComponent component, DatabaseConnection dbconn) { - // setup hints and fixes for possible resolution to connection issue - List fixes = new ArrayList<>(Collections.emptyList()); - List warnings = new ArrayList<>(Collections.emptyList()); - - // determine the selected line - String selection = component.getSelectedText(); - Document doc = component.getDocument(); - - // for selected lines with content - if (selection != null && selection.length() > 0) { - // use NbEditorUtilities.getLine() to get line from current document and offset, - int lineOffset = component.getSelectionStart() - 1; - int endOffset = lineOffset + selection.length(); - - Line currentLine = NbEditorUtilities.getLine(doc, lineOffset, false); - - // setup sql hints/fixes - try { - // identify possible fixes - - // hint to create a new connection - fixes.add(new SqlNewConnectionFix()); - // hint to add a new driver for connection - fixes.add(new SqlNewDriveFix()); - // hint to correction connection - show dialog to do so - fixes.add(new SqlConnectFix(component)); - - // setup ErrorDescription and add to warnings - warnings.add( - ErrorDescriptionFactory.createErrorDescription( - Severity.WARNING, - "DB Connection Issue", - fixes, - doc, - doc.createPosition(lineOffset), - doc.createPosition(endOffset) - ) - ); - } catch (BadLocationException ex) { - Exceptions.printStackTrace(ex); - } - } else { - // for non-selected lines - - // setup sql hints/fixes - try { - // identify possible fixes - - // hint to create a new connection - fixes.add(new SqlNewConnectionFix()); - // hint to add a new driver for connection - fixes.add(new SqlNewDriveFix()); - // hint to correction connection - show dialog to do so - fixes.add(new SqlConnectFix(component)); - - // no line is selected so add to initial position - // setup ErrorDescription and add to warnings - warnings.add( - ErrorDescriptionFactory.createErrorDescription( - Severity.WARNING, - "DB Connection Issue", - fixes, - doc, - doc.createPosition(0), - doc.createPosition(0) - ) - ); - } catch (BadLocationException ex) { - Exceptions.printStackTrace(ex); - } - HintsController.setErrors(doc, SQL_CONNECTION_HINT_ID, warnings); - } - } - private static DatabaseConnection findDBConn(JTextComponent component) { Lookup context = findContext(component); if (context == null) { @@ -264,93 +184,6 @@ private static TokenSequence getSQLTokenSequence(Document doc) { TokenHierarchy hierarchy = TokenHierarchy.get(doc); return hierarchy.tokenSequence(SQLTokenId.language()); } - - private static class SqlNewConnectionFix implements Fix { - @Override - public String getText() { - return "Create New Database connection."; - } - - @Override - public ChangeInfo implement() throws Exception { - - // select given connection - ConnectionManager cm = ConnectionManager.getDefault(); - DatabaseConnection dbconn = findDBConn(component); - - JDBCDriver driver = null; - if (dbconn == null) { - // no connection, have to establish driver and related details - cm.showAddConnectionDialog(null); - } - ChangeInfo results = new ChangeInfo(); - - return results; - } - - private void setupDriver() { - JDBCDriverManager dm = JDBCDriverManager.getDefault(); - JDBCDriver[] drivers = dm.getDrivers(); - - if (drivers == null || drivers.length ==0) { - dm.showAddDriverDialog(); - } - } - - public SqlNewConnectionFix() { - } - public SqlNewConnectionFix(DatabaseConnection conn) { - } - } - - /** - * This case handles when driver and connections are available but not connected - */ - private static class SqlConnectFix implements Fix { - - @Override - public String getText() { - return "Connect to database"; - } - - @Override - public ChangeInfo implement() throws Exception { - - SQLExecutionBaseAction.notifyNoDatabaseConnection(); - ChangeInfo results = new ChangeInfo(); - return results; - } - - public SqlConnectFix(JTextComponent applicableComponent) { - component = applicableComponent; - } - public SqlConnectFix() { - } - } - - /** - * This case handles when driver and connections are available but not connected - */ - private static class SqlNewDriveFix implements Fix { - - @Override - public String getText() { - return "Add a New Database Driver"; - } - - @Override - public ChangeInfo implement() throws Exception { - ConnectionManager cm = ConnectionManager.getDefault(); - JDBCDriverManager dm = JDBCDriverManager.getDefault(); - dm.showAddDriverDialog(); - - ChangeInfo results = new ChangeInfo(); - return results; - } - - public SqlNewDriveFix() { - } - } } From dce7e04924a259523941108f754173db84e71a2b Mon Sep 17 00:00:00 2001 From: Eric Bresie Date: Fri, 9 Apr 2021 11:09:42 -0500 Subject: [PATCH 08/16] Added notification of no connection when applicable. --- .../db/sql/editor/completion/SQLCompletionQuery.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionQuery.java b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionQuery.java index 54548cb7d63e..c2b93fa1a6fc 100644 --- a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionQuery.java +++ b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionQuery.java @@ -57,6 +57,7 @@ import org.netbeans.modules.db.sql.analyzer.SQLStatementKind; import org.netbeans.modules.db.sql.analyzer.UpdateStatement; import org.netbeans.modules.db.sql.editor.api.completion.SQLCompletionResultSet; +import org.netbeans.modules.db.sql.editor.ui.actions.SQLExecutionBaseAction; import org.netbeans.modules.db.sql.lexer.SQLTokenId; import org.netbeans.spi.editor.completion.CompletionResultSet; import org.netbeans.spi.editor.completion.support.AsyncCompletionQuery; @@ -210,6 +211,11 @@ SQLCompletionItems doQuery(SQLCompletionEnv env, Metadata metadata, Quoter quote anchorOffset = ident.anchorOffset; substitutionOffset = ident.substitutionOffset; SQLStatementKind kind = statement.getKind(); + + // give warning + if (dbconn == null) { + SQLExecutionBaseAction.notifyNoDatabaseConnection(); + } switch (kind) { case SELECT: completeSelect(); @@ -515,6 +521,7 @@ private void completeColumnSimpleIdent(String typedPrefix, boolean quoted) { if (tablesClause != null && !(tablesClause.getUnaliasedTableNames().isEmpty() && tablesClause.getAliasedTableNames().isEmpty())) { completeSimpleIdentBasedOnFromClause(typedPrefix, quoted); } else { + // have database metadata to populate if (metadata != null) { Schema defaultSchema = metadata.getDefaultSchema(); if (defaultSchema != null) { From 5fb502785a24869cbf9bcb9294628b0c4d274fd4 Mon Sep 17 00:00:00 2001 From: Eric Bresie Date: Fri, 9 Apr 2021 11:10:52 -0500 Subject: [PATCH 09/16] Changes getUnquotedIdentifier to return current text without checking with quoter if not available. --- .../modules/db/sql/analyzer/SQLStatementAnalyzer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/analyzer/SQLStatementAnalyzer.java b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/analyzer/SQLStatementAnalyzer.java index 4c17d2041285..155cc61f8100 100644 --- a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/analyzer/SQLStatementAnalyzer.java +++ b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/analyzer/SQLStatementAnalyzer.java @@ -238,9 +238,9 @@ protected QualIdent parseIdentifier() { } protected String getUnquotedIdentifier() { - // when quoter unavailable likely due to lack of connection + // quoter unavailable so returnas is if (quoter == null) { - return ""; + return seq.token().text().toString(); } return quoter.unquote(seq.token().text().toString()); } From 7809a7a88421dd5fd0d5852f13cf55e16d566e2b Mon Sep 17 00:00:00 2001 From: Eric Bresie Date: Fri, 9 Apr 2021 13:15:03 -0500 Subject: [PATCH 10/16] Removed notification warning. --- .../modules/db/sql/editor/completion/SQLCompletionQuery.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionQuery.java b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionQuery.java index c2b93fa1a6fc..a6f0dee6df61 100644 --- a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionQuery.java +++ b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionQuery.java @@ -212,10 +212,6 @@ SQLCompletionItems doQuery(SQLCompletionEnv env, Metadata metadata, Quoter quote substitutionOffset = ident.substitutionOffset; SQLStatementKind kind = statement.getKind(); - // give warning - if (dbconn == null) { - SQLExecutionBaseAction.notifyNoDatabaseConnection(); - } switch (kind) { case SELECT: completeSelect(); From eae8176ad6569f8aab423164f6f8b907dcba8a67 Mon Sep 17 00:00:00 2001 From: Eric Bresie Date: Fri, 9 Apr 2021 13:15:32 -0500 Subject: [PATCH 11/16] Removed unused imports. --- .../completion/SQLCompletionProvider.java | 20 ++----------------- 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionProvider.java b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionProvider.java index e1f98dd32da8..e94517a9634f 100644 --- a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionProvider.java +++ b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionProvider.java @@ -19,35 +19,19 @@ package org.netbeans.modules.db.sql.editor.completion; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import javax.swing.text.BadLocationException; import javax.swing.text.Document; import javax.swing.text.JTextComponent; -import org.netbeans.api.db.explorer.ConnectionManager; import org.netbeans.api.db.explorer.DatabaseConnection; -import org.netbeans.api.db.explorer.JDBCDriver; -import org.netbeans.api.db.explorer.JDBCDriverManager; import org.netbeans.api.lexer.Language; import org.netbeans.api.lexer.TokenHierarchy; import org.netbeans.api.lexer.TokenSequence; import org.netbeans.modules.db.api.sql.execute.SQLExecution; import org.netbeans.modules.db.sql.editor.ui.actions.SQLExecutionBaseAction; import org.netbeans.modules.db.sql.lexer.SQLTokenId; -import org.netbeans.modules.editor.NbEditorUtilities; import org.netbeans.spi.editor.completion.CompletionProvider; import org.netbeans.spi.editor.completion.CompletionTask; import org.netbeans.spi.editor.completion.support.AsyncCompletionTask; -import org.netbeans.spi.editor.hints.ChangeInfo; -import org.netbeans.spi.editor.hints.ErrorDescription; -import org.netbeans.spi.editor.hints.ErrorDescriptionFactory; -import org.netbeans.spi.editor.hints.Fix; -import org.netbeans.spi.editor.hints.HintsController; -import org.netbeans.spi.editor.hints.Severity; import org.openide.awt.StatusDisplayer; -import org.openide.text.Line; -import org.openide.util.Exceptions; import org.openide.util.Lookup; import org.openide.util.NbBundle; @@ -68,7 +52,7 @@ public CompletionTask createTask(int queryType, JTextComponent component) { /* to support DB related completion tasks (i.e. auto populating table names or db columns for given schema) check for connection */ DatabaseConnection dbconn = findDBConn(component); - + return new AsyncCompletionTask(new SQLCompletionQuery(dbconn), component); } @@ -113,7 +97,7 @@ public int getAutoQueryTypes(JTextComponent component, String typedText) { if (dbconn != null && dbconn.getJDBCConnection() == null) { String message = NbBundle.getMessage(SQLCompletionProvider.class, "MSG_NotConnected"); StatusDisplayer.getDefault().setStatusText(message); - SQLExecutionBaseAction.notifyNoDatabaseConnection(); + SQLExecutionBaseAction.notifyNoDatabaseConnection(); // XXX: Maybe add content specific "fixs" } return COMPLETION_QUERY_TYPE; From 84b35089edc62924e8a0139a9027f32909d90161 Mon Sep 17 00:00:00 2001 From: Eric Bresie Date: Sat, 20 Mar 2021 13:05:44 -0500 Subject: [PATCH 12/16] [NETBEANS-189] Allows auto-completion even with no connection --- ide/db.sql.editor/nbproject/project.xml | 705 +++++++++--------- .../db/sql/analyzer/SQLStatementAnalyzer.java | 5 +- .../completion/SQLCompletionProvider.java | 270 ++++++- .../editor/completion/SQLCompletionQuery.java | 217 ++++-- .../db/sql/editor/resources/Bundle.properties | 1 + .../modules/db/sql/editor/resources/layer.xml | 4 +- 6 files changed, 752 insertions(+), 450 deletions(-) diff --git a/ide/db.sql.editor/nbproject/project.xml b/ide/db.sql.editor/nbproject/project.xml index 90faa558fdda..d22456274a95 100644 --- a/ide/db.sql.editor/nbproject/project.xml +++ b/ide/db.sql.editor/nbproject/project.xml @@ -1,341 +1,364 @@ - - - - org.netbeans.modules.apisupport.project - - - org.netbeans.modules.db.sql.editor - - - org.netbeans.modules.csl.api - - - - 2 - 2.27 - - - - org.netbeans.modules.csl.types - - - - 1 - 1.0 - - - - org.netbeans.modules.db - - - - 1 - - - - - org.netbeans.modules.db.core - - - - 1.0 - - - - org.netbeans.modules.db.metadata.model - - - - 0-1 - 0.8 - - - - org.netbeans.modules.dbapi - - - - 1.2 - - - - org.netbeans.modules.editor - - - - 3 - 1.53 - - - - org.netbeans.modules.editor.bracesmatching - - - - 0-1 - 1.22 - - - - org.netbeans.modules.editor.completion - - - - 1 - 1.12 - - - - org.netbeans.modules.editor.document - - - - 1.3 - - - - org.netbeans.modules.editor.fold - - - - 1 - 1.42 - - - - org.netbeans.modules.editor.lib - - - - 3 - 4.0 - - - - org.netbeans.modules.editor.lib2 - - - - 1 - 2.0 - - - - org.netbeans.modules.editor.mimelookup - - - - 1 - 1.26 - - - - org.netbeans.modules.lexer - - - - 2 - 1.27 - - - - org.netbeans.modules.projectapi - - - - 1 - 1.26 - - - - org.netbeans.modules.queries - - - - 1 - 1.15 - - - - org.netbeans.swing.plaf - - - - 1.34 - - - - org.openide.actions - - - - 6.2 - - - - org.openide.awt - - - - 6.7 - - - - org.openide.dialogs - - - - 6.2 - - - - org.openide.explorer - - - - 6.8 - - - - org.openide.filesystems - - - - 9.0 - - - - org.openide.loaders - - - - 7.61 - - - - org.openide.modules - - - - 6.2 - - - - org.openide.nodes - - - - 7.23 - - - - org.openide.text - - - - 6.16 - - - - org.openide.util - - - - 9.3 - - - - org.openide.util.lookup - - - - 8.0 - - - - org.openide.util.ui - - - - 9.3 - - - - - - unit - - org.netbeans.libs.junit4 - - - - org.netbeans.modules.csl.api - - - - - - org.netbeans.modules.db - - - - - org.netbeans.modules.db.metadata.model - - - - - org.netbeans.modules.editor.mimelookup - - - - org.netbeans.modules.editor.mimelookup.impl - - - - org.netbeans.modules.lexer - - - - - org.netbeans.modules.nbjunit - - - - - org.netbeans.modules.projectapi.nb - - - org.openide.util.lookup - - - - - - - com.sun.tools.odb - org.netbeans.modules.php.editor - org.netbeans.modules.db.sql.editor.api.completion - - - - + + + + org.netbeans.modules.apisupport.project + + + org.netbeans.modules.db.sql.editor + + + org.netbeans.modules.csl.api + + + + 2 + 2.27 + + + + org.netbeans.modules.csl.types + + + + 1 + 1.0 + + + + org.netbeans.modules.db + + + + 1 + + + + + org.netbeans.modules.db.core + + + + 1.0 + + + + org.netbeans.modules.db.metadata.model + + + + 0-1 + 0.8 + + + + org.netbeans.modules.dbapi + + + + 1.2 + + + + org.netbeans.modules.editor + + + + 3 + 1.53 + + + + org.netbeans.modules.editor.bracesmatching + + + + 0-1 + 1.22 + + + + org.netbeans.modules.editor.completion + + + + 1 + 1.12 + + + + org.netbeans.modules.editor.document + + + + 1.3 + + + + org.netbeans.modules.editor.fold + + + + 1 + 1.42 + + + + org.netbeans.modules.editor.lib + + + + 3 + 4.0 + + + + org.netbeans.modules.editor.lib2 + + + + 1 + 2.0 + + + + org.netbeans.modules.editor.mimelookup + + + + 1 + 1.26 + + + + org.netbeans.modules.lexer + + + + 2 + 1.27 + + + + org.netbeans.modules.projectapi + + + + 1 + 1.26 + + + + org.netbeans.modules.queries + + + + 1 + 1.15 + + + + org.netbeans.spi.editor.hints + + + + 0 + 1.53 + + + + org.netbeans.spi.java.hints + + + + 1.42 + + + + org.netbeans.swing.plaf + + + + 1.34 + + + + org.openide.actions + + + + 6.2 + + + + org.openide.awt + + + + 6.7 + + + + org.openide.dialogs + + + + 6.2 + + + + org.openide.explorer + + + + 6.8 + + + + org.openide.filesystems + + + + 9.0 + + + + org.openide.loaders + + + + 7.61 + + + + org.openide.modules + + + + 6.2 + + + + org.openide.nodes + + + + 7.23 + + + + org.openide.text + + + + 6.16 + + + + org.openide.util + + + + 9.3 + + + + org.openide.util.lookup + + + + 8.0 + + + + org.openide.util.ui + + + + 9.3 + + + + + + unit + + org.netbeans.libs.junit4 + + + + org.netbeans.modules.csl.api + + + + + + org.netbeans.modules.db + + + + + org.netbeans.modules.db.metadata.model + + + + + org.netbeans.modules.editor.mimelookup + + + + org.netbeans.modules.editor.mimelookup.impl + + + + org.netbeans.modules.lexer + + + + + org.netbeans.modules.nbjunit + + + + + org.netbeans.modules.parsing.nb + + + + + + org.netbeans.modules.projectapi.nb + + + org.openide.util.lookup + + + + + + + com.sun.tools.odb + org.netbeans.modules.php.editor + org.netbeans.modules.db.sql.editor.api.completion + + + + diff --git a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/analyzer/SQLStatementAnalyzer.java b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/analyzer/SQLStatementAnalyzer.java index 299e2a39140e..4c17d2041285 100644 --- a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/analyzer/SQLStatementAnalyzer.java +++ b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/analyzer/SQLStatementAnalyzer.java @@ -34,7 +34,6 @@ import org.netbeans.modules.db.sql.analyzer.SQLStatement.Context; import org.netbeans.modules.db.sql.editor.StringUtils; import org.netbeans.modules.db.sql.lexer.SQLTokenId; - /** * * @author Jiri Rechtacek, Jiri Skrivanek @@ -239,6 +238,10 @@ protected QualIdent parseIdentifier() { } protected String getUnquotedIdentifier() { + // when quoter unavailable likely due to lack of connection + if (quoter == null) { + return ""; + } return quoter.unquote(seq.token().text().toString()); } diff --git a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionProvider.java b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionProvider.java index 8d3aa3d8a6a9..3b47b1cf4fe0 100644 --- a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionProvider.java +++ b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionProvider.java @@ -19,20 +19,35 @@ package org.netbeans.modules.db.sql.editor.completion; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import javax.swing.text.BadLocationException; import javax.swing.text.Document; import javax.swing.text.JTextComponent; +import org.netbeans.api.db.explorer.ConnectionManager; import org.netbeans.api.db.explorer.DatabaseConnection; -import org.netbeans.api.editor.completion.Completion; +import org.netbeans.api.db.explorer.JDBCDriver; +import org.netbeans.api.db.explorer.JDBCDriverManager; import org.netbeans.api.lexer.Language; import org.netbeans.api.lexer.TokenHierarchy; import org.netbeans.api.lexer.TokenSequence; import org.netbeans.modules.db.api.sql.execute.SQLExecution; import org.netbeans.modules.db.sql.editor.ui.actions.SQLExecutionBaseAction; import org.netbeans.modules.db.sql.lexer.SQLTokenId; +import org.netbeans.modules.editor.NbEditorUtilities; import org.netbeans.spi.editor.completion.CompletionProvider; import org.netbeans.spi.editor.completion.CompletionTask; import org.netbeans.spi.editor.completion.support.AsyncCompletionTask; +import org.netbeans.spi.editor.hints.ChangeInfo; +import org.netbeans.spi.editor.hints.ErrorDescription; +import org.netbeans.spi.editor.hints.ErrorDescriptionFactory; +import org.netbeans.spi.editor.hints.Fix; +import org.netbeans.spi.editor.hints.HintsController; +import org.netbeans.spi.editor.hints.Severity; import org.openide.awt.StatusDisplayer; +import org.openide.text.Line; +import org.openide.util.Exceptions; import org.openide.util.Lookup; import org.openide.util.NbBundle; @@ -41,42 +56,149 @@ * @author Andrei Badea */ public class SQLCompletionProvider implements CompletionProvider { + private static final String SQL_CONNECTION_HINT_ID = "sql_connection_hint"; + private static JTextComponent component = null; + private static DatabaseConnection dbconn = null; + @Override public CompletionTask createTask(int queryType, JTextComponent component) { - if (queryType == CompletionProvider.COMPLETION_QUERY_TYPE || queryType == CompletionProvider.COMPLETION_ALL_QUERY_TYPE) { + if (queryType == CompletionProvider.COMPLETION_QUERY_TYPE || + queryType == CompletionProvider.COMPLETION_ALL_QUERY_TYPE) { + + /* to support DB related completion tasks (i.e. auto populating table + names or db columns for given schema) check for connection */ DatabaseConnection dbconn = findDBConn(component); - if (dbconn == null) { - // XXX perhaps should have an item in the completion instead? - Completion.get().hideAll(); - SQLExecutionBaseAction.notifyNoDatabaseConnection(); - return null; + // No database connection set or active + if (SQLCompletionProvider.dbconn == null) { + createSuggestions(component,dbconn); } + return new AsyncCompletionTask(new SQLCompletionQuery(dbconn), component); } + + // not a completion query type so return nothing return null; } + /** + * getAutoQueryTypes is invoked to check whether a popup with suggestions + * should be shown without the user explicitly asking for it. + * + * If either #getAutoQueryTypes return a non-zero value or the user + * explicitly asks for completion, #createTask is invoked with the + * requested type. In case of SQL see + * org.netbeans.modules.db.sql.editor.completion.SQLCompletionQuery. + * + * @param component + * @param typedText + * @return + */ public int getAutoQueryTypes(JTextComponent component, String typedText) { + // XXX: Check if "enable/disable" autocomplete is setting. See NETBEANS-188 + + // If "." has not been typed then acceptable to start checking for options. if (!".".equals(typedText)) { // NOI18N return 0; } + // check typed text if dot is present at the selected offset if (!isDotAtOffset(component, component.getSelectionStart() - 1)) { return 0; } + + // check if there is a DB connection DatabaseConnection dbconn = findDBConn(component); if (dbconn == null) { String message = NbBundle.getMessage(SQLCompletionProvider.class, "MSG_NoDatabaseConnection"); StatusDisplayer.getDefault().setStatusText(message); - return 0; + createSuggestions(component, dbconn); + SQLExecutionBaseAction.notifyNoDatabaseConnection(); } - if (dbconn.getJDBCConnection() == null) { + + // check if DB connection is active + if (dbconn != null && dbconn.getJDBCConnection() == null) { String message = NbBundle.getMessage(SQLCompletionProvider.class, "MSG_NotConnected"); StatusDisplayer.getDefault().setStatusText(message); - return 0; + SQLExecutionBaseAction.notifyNoDatabaseConnection(); + // XXX: Maybe add content specific "fixs" } return COMPLETION_QUERY_TYPE; } + private void createSuggestions(JTextComponent component, DatabaseConnection dbconn) { + // setup hints and fixes for possible resolution to connection issue + List fixes = new ArrayList<>(Collections.emptyList()); + List warnings = new ArrayList<>(Collections.emptyList()); + + // determine the selected line + String selection = component.getSelectedText(); + Document doc = component.getDocument(); + + // for selected lines with content + if (selection != null && selection.length() > 0) { + // use NbEditorUtilities.getLine() to get line from current document and offset, + int lineOffset = component.getSelectionStart() - 1; + int endOffset = lineOffset + selection.length(); + + Line currentLine = NbEditorUtilities.getLine(doc, lineOffset, false); + + // setup sql hints/fixes + try { + // identify possible fixes + + // hint to create a new connection + fixes.add(new SqlNewConnectionFix()); + // hint to add a new driver for connection + fixes.add(new SqlNewDriveFix()); + // hint to correction connection - show dialog to do so + fixes.add(new SqlConnectFix(component)); + + // setup ErrorDescription and add to warnings + warnings.add( + ErrorDescriptionFactory.createErrorDescription( + Severity.WARNING, + "DB Connection Issue", + fixes, + doc, + doc.createPosition(lineOffset), + doc.createPosition(endOffset) + ) + ); + } catch (BadLocationException ex) { + Exceptions.printStackTrace(ex); + } + } else { + // for non-selected lines + + // setup sql hints/fixes + try { + // identify possible fixes + + // hint to create a new connection + fixes.add(new SqlNewConnectionFix()); + // hint to add a new driver for connection + fixes.add(new SqlNewDriveFix()); + // hint to correction connection - show dialog to do so + fixes.add(new SqlConnectFix(component)); + + // no line is selected so add to initial position + // setup ErrorDescription and add to warnings + warnings.add( + ErrorDescriptionFactory.createErrorDescription( + Severity.WARNING, + "DB Connection Issue", + fixes, + doc, + doc.createPosition(0), + doc.createPosition(0) + ) + ); + } catch (BadLocationException ex) { + Exceptions.printStackTrace(ex); + } + HintsController.setErrors(doc, SQL_CONNECTION_HINT_ID, warnings); + } + } + private static DatabaseConnection findDBConn(JTextComponent component) { Lookup context = findContext(component); if (context == null) { @@ -101,24 +223,35 @@ private static Lookup findContext(JTextComponent component) { return null; } + /** + * For given component object's doc model, determine if given offset + * has applicable dot delimiter token + * @param component + * @param offset + * @return + */ private static boolean isDotAtOffset(JTextComponent component, final int offset) { final Document doc = component.getDocument(); final boolean[] result = { false }; - doc.render(new Runnable() { - public void run() { - TokenSequence seq = getSQLTokenSequence(doc); - if (seq == null) { - return; - } - seq.move(offset); - if (!seq.moveNext() && !seq.movePrevious()) { - return; - } - if (seq.offset() != offset) { - return; - } - result[0] = (seq.token().id() == SQLTokenId.DOT); + // trigger internal model rendering based on SQL tokens + doc.render(() -> { + TokenSequence seq = getSQLTokenSequence(doc); + // no SQL tokens found; done checking + if (seq == null) { + return; } + // in the sequence move to provided offset location + seq.move(offset); + // no next or previous so done looking for tokens; done checking + if (!seq.moveNext() && !seq.movePrevious()) { + return; + } + // if offset not consistent with sequence offset done checking + if (seq.offset() != offset) { + return; + } + // confirm token ID is applicable SQL "dot" token + result[0] = (seq.token().id() == SQLTokenId.DOT); }); return result[0]; } @@ -131,4 +264,93 @@ private static TokenSequence getSQLTokenSequence(Document doc) { TokenHierarchy hierarchy = TokenHierarchy.get(doc); return hierarchy.tokenSequence(SQLTokenId.language()); } + + private static class SqlNewConnectionFix implements Fix { + @Override + public String getText() { + return "Create New Database connection."; + } + + @Override + public ChangeInfo implement() throws Exception { + + // select given connection + ConnectionManager cm = ConnectionManager.getDefault(); + DatabaseConnection dbconn = findDBConn(component); + + JDBCDriver driver = null; + if (dbconn == null) { + // no connection, have to establish driver and related details + cm.showAddConnectionDialog(null); + } + ChangeInfo results = new ChangeInfo(); + + return results; + } + + private void setupDriver() { + JDBCDriverManager dm = JDBCDriverManager.getDefault(); + JDBCDriver[] drivers = dm.getDrivers(); + + if (drivers == null || drivers.length ==0) { + dm.showAddDriverDialog(); + } + } + + public SqlNewConnectionFix() { + } + public SqlNewConnectionFix(DatabaseConnection conn) { + } + } + + /** + * This case handles when driver and connections are available but not connected + */ + private static class SqlConnectFix implements Fix { + + @Override + public String getText() { + return "Connect to database"; + } + + @Override + public ChangeInfo implement() throws Exception { + + SQLExecutionBaseAction.notifyNoDatabaseConnection(); + ChangeInfo results = new ChangeInfo(); + return results; + } + + public SqlConnectFix(JTextComponent applicableComponent) { + component = applicableComponent; + } + public SqlConnectFix() { + } + } + + /** + * This case handles when driver and connections are available but not connected + */ + private static class SqlNewDriveFix implements Fix { + + @Override + public String getText() { + return "Add a New Database Driver"; + } + + @Override + public ChangeInfo implement() throws Exception { + ConnectionManager cm = ConnectionManager.getDefault(); + JDBCDriverManager dm = JDBCDriverManager.getDefault(); + dm.showAddDriverDialog(); + + ChangeInfo results = new ChangeInfo(); + return results; + } + + public SqlNewDriveFix() { + } + } } + + diff --git a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionQuery.java b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionQuery.java index 57fd2a334696..54548cb7d63e 100644 --- a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionQuery.java +++ b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionQuery.java @@ -120,23 +120,42 @@ public void query(SQLCompletionResultSet resultSet, SQLCompletionEnv newEnv) { private void doQuery(final SQLCompletionEnv newEnv) { try { - DBConnMetadataModelManager.get(dbconn).runReadAction(new Action() { - @Override - public void run(Metadata metadata) { - Connection conn = dbconn.getJDBCConnection(); - if (conn == null) { - return; - } - Quoter quoter = null; - try { - DatabaseMetaData dmd = conn.getMetaData(); - quoter = SQLIdentifiers.createQuoter(dmd); - } catch (SQLException e) { - throw new MetadataException(e); + // DB Connection available + if (dbconn != null) { + // DB connection present so + DBConnMetadataModelManager.get(dbconn).runReadAction(new Action() { + @Override + public void run(Metadata metadata) { + Connection conn = null; + if (dbconn != null) { + conn = dbconn.getJDBCConnection(); + } + Quoter quoter = null; + try { + /* if connection available allow for bb meta data + and quoter to help in auto completion */ + if (conn != null) { + // get Database meta data + DatabaseMetaData dmd = conn.getMetaData(); + quoter = SQLIdentifiers.createQuoter(dmd); + } + } catch (SQLException e) { + throw new MetadataException(e); + } + /* if quoter available then allow for query for + auto completion to occur, else avoid this sort of + activities when quoter/connection not available*/ + if (quoter != null) { + doQuery(newEnv, metadata, quoter); + } else { + return; + } } - doQuery(newEnv, metadata, quoter); - } - }); + }); + } else { + // No DB Connection established presently + doQuery(newEnv, metadata, quoter); + } } catch (MetadataModelException e) { reportError(e); } @@ -149,30 +168,45 @@ SQLCompletionItems doQuery(SQLCompletionEnv env, Metadata metadata, Quoter quote this.quoter = quoter; anchorOffset = -1; substitutionOffset = 0; + + // address empty env so add basic keywords items = new SQLCompletionItems(quoter, env.getSubstitutionHandler()); + if (env.getTokenSequence().isEmpty()) { completeKeyword("SELECT", "INSERT", "DELETE", "DROP", "UPDATE", "CREATE"); //NOI18N return items; } - statement = SQLStatementAnalyzer.analyze(env.getTokenSequence(), quoter); + + // not empty so address possible statement cases + statement = SQLStatementAnalyzer.analyze(env.getTokenSequence(), quoter); + + // unable to find relevant case so include basic keywords items if (statement == null) { completeKeyword("SELECT", "INSERT", "DELETE", "DROP", "UPDATE", "CREATE"); //NOI18N return items; } + + // found a create case so update to include create case items if (statement.getKind() == SQLStatementKind.CREATE && ((CreateStatement) statement).hasBody()) { completeCreateBody(); return items; } + + // checking context of offset to see if applicable; if not then set to basics context = statement.getContextAtOffset(env.getCaretOffset()); if (context == null) { completeKeyword("SELECT", "INSERT", "DELETE", "DROP", "UPDATE", "CREATE"); //NOI18N return items; } + + // from context look for identifiers; if none then return current context ident = findIdentifier(); if (ident == null) { completeKeyword(context); return items; } + + // from ident anchorif identifier identified then determine kin anchorOffset = ident.anchorOffset; substitutionOffset = ident.substitutionOffset; SQLStatementKind kind = statement.getKind(); @@ -474,40 +508,45 @@ private void completeColumnWithDefinedTuple(Identifier ident) { } } - /** Adds columns, tuples, schemas and catalogs according to given identifier. */ + /** + * Adds columns, tuples, schema and catalogs according to given identifier. + */ private void completeColumnSimpleIdent(String typedPrefix, boolean quoted) { if (tablesClause != null && !(tablesClause.getUnaliasedTableNames().isEmpty() && tablesClause.getAliasedTableNames().isEmpty())) { completeSimpleIdentBasedOnFromClause(typedPrefix, quoted); } else { - Schema defaultSchema = metadata.getDefaultSchema(); - if (defaultSchema != null) { - // All columns in default schema, but only if a prefix has been typed, otherwise there - // would be too many columns. - if (typedPrefix != null) { - for (Table table : defaultSchema.getTables()) { - items.addColumns(table, typedPrefix, quoted, substitutionOffset); + if (metadata != null) { + Schema defaultSchema = metadata.getDefaultSchema(); + if (defaultSchema != null) { + // All columns in default schema, but only if a prefix has been typed, otherwise there + // would be too many columns. + if (typedPrefix != null) { + for (Table table : defaultSchema.getTables()) { + items.addColumns(table, typedPrefix, quoted, substitutionOffset); + } + if (includeViews) { + for (View view : defaultSchema.getViews()) { + items.addColumns(view, typedPrefix, quoted, substitutionOffset); + } + } } + // All tuples in default schema. + items.addTables(defaultSchema, null, typedPrefix, quoted, substitutionOffset); if (includeViews) { - for (View view : defaultSchema.getViews()) { - items.addColumns(view, typedPrefix, quoted, substitutionOffset); - } + items.addViews(defaultSchema, null, typedPrefix, quoted, substitutionOffset); } } - // All tuples in default schema. - items.addTables(defaultSchema, null, typedPrefix, quoted, substitutionOffset); - if (includeViews) { - items.addViews(defaultSchema, null, typedPrefix, quoted, substitutionOffset); - } + // All schemas. + Catalog defaultCatalog = metadata.getDefaultCatalog(); + items.addSchemas(defaultCatalog, null, typedPrefix, quoted, substitutionOffset); + // All catalogs. + items.addCatalogs(metadata, null, typedPrefix, quoted, substitutionOffset); } - // All schemas. - Catalog defaultCatalog = metadata.getDefaultCatalog(); - items.addSchemas(defaultCatalog, null, typedPrefix, quoted, substitutionOffset); - // All catalogs. - items.addCatalogs(metadata, null, typedPrefix, quoted, substitutionOffset); } } private void completeColumnWithTupleIfSimpleIdent(String typedPrefix, boolean quoted) { + if (metadata != null) { Schema defaultSchema = metadata.getDefaultSchema(); if (defaultSchema != null) { // All columns in default schema, but only if a prefix has been typed, otherwise there @@ -534,6 +573,7 @@ private void completeColumnWithTupleIfSimpleIdent(String typedPrefix, boolean qu items.addSchemas(defaultCatalog, null, typedPrefix, quoted, substitutionOffset); // All catalogs. items.addCatalogs(metadata, null, typedPrefix, quoted, substitutionOffset); + } } private void completeColumnWithTupleIfQualIdent(QualIdent fullyTypedIdent, String lastPrefix, boolean quoted) { @@ -587,19 +627,22 @@ private void completeColumnQualIdent(QualIdent fullyTypedIdent, String lastPrefi /** Adds all tuples from default schema, all schemas from defaultcatalog * and all catalogs. */ private void completeTupleSimpleIdent(String typedPrefix, boolean quoted) { - Schema defaultSchema = metadata.getDefaultSchema(); - if (defaultSchema != null) { - // All tuples in default schema. - items.addTables(defaultSchema, null, typedPrefix, quoted, substitutionOffset); - if (includeViews) { - items.addViews(defaultSchema, null, typedPrefix, quoted, substitutionOffset); + // connection metadata available so add to available items + if (metadata != null ){ + Schema defaultSchema = metadata.getDefaultSchema(); + if (defaultSchema != null) { + // All tuples in default schema. + items.addTables(defaultSchema, null, typedPrefix, quoted, substitutionOffset); + if (includeViews) { + items.addViews(defaultSchema, null, typedPrefix, quoted, substitutionOffset); + } } + // All schemas. + Catalog defaultCatalog = metadata.getDefaultCatalog(); + items.addSchemas(defaultCatalog, null, typedPrefix, quoted, substitutionOffset); + // All catalogs. + items.addCatalogs(metadata, null, typedPrefix, quoted, substitutionOffset); } - // All schemas. - Catalog defaultCatalog = metadata.getDefaultCatalog(); - items.addSchemas(defaultCatalog, null, typedPrefix, quoted, substitutionOffset); - // All catalogs. - items.addCatalogs(metadata, null, typedPrefix, quoted, substitutionOffset); } /** Adds all tuples in schema get from fully qualified identifier or all @@ -643,6 +686,7 @@ private void completeSimpleIdentBasedOnFromClause(String typedPrefix, boolean qu items.addColumns(tuple, typedPrefix, quoted, substitutionOffset); } // Tuples from default schema, restricted to non-aliased tuple names in the FROM clause. + if (metadata != null ) { Schema defaultSchema = metadata.getDefaultSchema(); if (defaultSchema != null) { Set simpleTupleNames = new TreeSet(); @@ -674,6 +718,7 @@ private void completeSimpleIdentBasedOnFromClause(String typedPrefix, boolean qu Catalog defaultCatalog = metadata.getDefaultCatalog(); items.addSchemas(defaultCatalog, schemaNames, typedPrefix, quoted, substitutionOffset); items.addCatalogs(metadata, catalogNames, typedPrefix, quoted, substitutionOffset); + } } private void completeQualIdentBasedOnFromClause(QualIdent fullyTypedIdent, String lastPrefix, boolean quoted) { @@ -744,7 +789,7 @@ private void completeCatalog(Catalog catalog, String prefix, boolean quoted) { } private Catalog resolveCatalog(QualIdent catalogName) { - if (catalogName.isSimple()) { + if (metadata != null && catalogName.isSimple()) { return metadata.getCatalog(catalogName.getSimpleName()); } return null; @@ -752,23 +797,25 @@ private Catalog resolveCatalog(QualIdent catalogName) { private Schema resolveSchema(QualIdent schemaName) { Schema schema = null; - switch (schemaName.size()) { - case 1: - Catalog catalog = metadata.getDefaultCatalog(); - schema = catalog.getSchema(schemaName.getSimpleName()); - break; - case 2: - catalog = metadata.getCatalog(schemaName.getFirstQualifier()); - if (catalog != null) { + if (metadata != null) { + switch (schemaName.size()) { + case 1: + Catalog catalog = metadata.getDefaultCatalog(); schema = catalog.getSchema(schemaName.getSimpleName()); - } - break; + break; + case 2: + catalog = metadata.getCatalog(schemaName.getFirstQualifier()); + if (catalog != null) { + schema = catalog.getSchema(schemaName.getSimpleName()); + } + break; + } } return schema; } private Tuple resolveTuple(QualIdent tupleName) { - if (tupleName == null) { + if (tupleName == null || metadata == null) { return null; } Tuple tuple = null; @@ -918,7 +965,7 @@ private Identifier findIdentifier() { String part; int offset = caretOffset - seq.offset(); String tokenText = seq.token().text().toString(); - if (offset > 0 && offset < seq.token().length()) { + if (offset > 0 && offset < seq.token().length() && quoter != null) { String quoteString = quoter.getQuoteString(); if (tokenText.startsWith(quoteString) && tokenText.endsWith(quoteString) && offset == tokenText.length() - 1) { // identifier inside closed quotes and cursor before ending quote ("foo|") @@ -978,6 +1025,10 @@ private Identifier findIdentifier() { } /** + * Used to create an Identifier based on current parts of the expression so far, + * if the details are "Complete" and the offset of given prefix involved. + * + * @param parts the list of potentail * @param lastPrefixOffset the offset of the last prefix in the identifier, or * if no such prefix, the caret offset. * @return @@ -993,30 +1044,32 @@ private Identifier createIdentifier(List parts, boolean incomplete, int } // Fine, nothing was typed. } else { - if (!incomplete) { - lastPrefix = parts.remove(parts.size() - 1); - String quoteString = quoter.getQuoteString(); - if (quoteString.length() > 0 && lastPrefix.startsWith(quoteString)) { - if (lastPrefix.endsWith(quoteString) && lastPrefix.length() > quoteString.length()) { - // User typed '"foo"."bar"|', can't complete that. + if (quoter != null ) { + if (!incomplete) { + lastPrefix = parts.remove(parts.size() - 1); + String quoteString = quoter.getQuoteString(); + if (quoteString.length() > 0 && lastPrefix.startsWith(quoteString)) { + if (lastPrefix.endsWith(quoteString) && lastPrefix.length() > quoteString.length()) { + // User typed '"foo"."bar"|', can't complete that. + return null; + } + int lastPrefixLength = lastPrefix.length(); + lastPrefix = quoter.unquote(lastPrefix); + lastPrefixOffset = lastPrefixOffset + (lastPrefixLength - lastPrefix.length()); + quoted = true; + } else if (quoteString.length() > 0 && lastPrefix.endsWith(quoteString)) { + // User typed '"foo".bar"|', can't complete. return null; } - int lastPrefixLength = lastPrefix.length(); - lastPrefix = quoter.unquote(lastPrefix); - lastPrefixOffset = lastPrefixOffset + (lastPrefixLength - lastPrefix.length()); - quoted = true; - } else if (quoteString.length() > 0 && lastPrefix.endsWith(quoteString)) { - // User typed '"foo".bar"|', can't complete. - return null; } - } - for (int i = 0; i < parts.size(); i++) { - String unquoted = quoter.unquote(parts.get(i)); - if (unquoted.length() == 0) { - // User typed something like '"foo".""."bar|'. - return null; + for (int i = 0; i < parts.size(); i++) { + String unquoted = quoter.unquote(parts.get(i)); + if (unquoted.length() == 0) { + // User typed something like '"foo".""."bar|'. + return null; + } + parts.set(i, unquoted); } - parts.set(i, unquoted); } } return new Identifier(new QualIdent(parts), lastPrefix, quoted, lastPrefixOffset, substOffset); diff --git a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/resources/Bundle.properties b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/resources/Bundle.properties index 87ec6b6d14ba..3815692f9a89 100644 --- a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/resources/Bundle.properties +++ b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/resources/Bundle.properties @@ -41,3 +41,4 @@ sql-keyword=Keyword sql-errors=Error sql-dot=Period +LAB_db_sql_editor_annotation_warn="Select Connection from the combo box at the top of the SQL Editor window." diff --git a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/resources/layer.xml b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/resources/layer.xml index d989aafb01aa..7257cdcdf705 100644 --- a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/resources/layer.xml +++ b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/resources/layer.xml @@ -58,7 +58,7 @@ - + @@ -110,7 +110,7 @@ - + From c82fd4a48bc2e86f7481721a99f3316e779d13ef Mon Sep 17 00:00:00 2001 From: Eric Bresie Date: Sun, 11 Apr 2021 13:26:19 -0500 Subject: [PATCH 13/16] [NETBEANS-189] Allows auto-completion even with no connection --- ide/db.sql.editor/nbproject/project.xml | 720 +++++++++--------- .../db/sql/analyzer/SQLStatementAnalyzer.java | 4 +- .../completion/SQLCompletionProvider.java | 190 +---- .../editor/completion/SQLCompletionQuery.java | 3 + .../db/sql/editor/resources/Bundle.properties | 2 - 5 files changed, 363 insertions(+), 556 deletions(-) diff --git a/ide/db.sql.editor/nbproject/project.xml b/ide/db.sql.editor/nbproject/project.xml index d22456274a95..68f7a346e4ea 100644 --- a/ide/db.sql.editor/nbproject/project.xml +++ b/ide/db.sql.editor/nbproject/project.xml @@ -1,364 +1,356 @@ - - - - org.netbeans.modules.apisupport.project - - - org.netbeans.modules.db.sql.editor - - - org.netbeans.modules.csl.api - - - - 2 - 2.27 - - - - org.netbeans.modules.csl.types - - - - 1 - 1.0 - - - - org.netbeans.modules.db - - - - 1 - - - - - org.netbeans.modules.db.core - - - - 1.0 - - - - org.netbeans.modules.db.metadata.model - - - - 0-1 - 0.8 - - - - org.netbeans.modules.dbapi - - - - 1.2 - - - - org.netbeans.modules.editor - - - - 3 - 1.53 - - - - org.netbeans.modules.editor.bracesmatching - - - - 0-1 - 1.22 - - - - org.netbeans.modules.editor.completion - - - - 1 - 1.12 - - - - org.netbeans.modules.editor.document - - - - 1.3 - - - - org.netbeans.modules.editor.fold - - - - 1 - 1.42 - - - - org.netbeans.modules.editor.lib - - - - 3 - 4.0 - - - - org.netbeans.modules.editor.lib2 - - - - 1 - 2.0 - - - - org.netbeans.modules.editor.mimelookup - - - - 1 - 1.26 - - - - org.netbeans.modules.lexer - - - - 2 - 1.27 - - - - org.netbeans.modules.projectapi - - - - 1 - 1.26 - - - - org.netbeans.modules.queries - - - - 1 - 1.15 - - - - org.netbeans.spi.editor.hints - - - - 0 - 1.53 - - - - org.netbeans.spi.java.hints - - - - 1.42 - - - - org.netbeans.swing.plaf - - - - 1.34 - - - - org.openide.actions - - - - 6.2 - - - - org.openide.awt - - - - 6.7 - - - - org.openide.dialogs - - - - 6.2 - - - - org.openide.explorer - - - - 6.8 - - - - org.openide.filesystems - - - - 9.0 - - - - org.openide.loaders - - - - 7.61 - - - - org.openide.modules - - - - 6.2 - - - - org.openide.nodes - - - - 7.23 - - - - org.openide.text - - - - 6.16 - - - - org.openide.util - - - - 9.3 - - - - org.openide.util.lookup - - - - 8.0 - - - - org.openide.util.ui - - - - 9.3 - - - - - - unit - - org.netbeans.libs.junit4 - - - - org.netbeans.modules.csl.api - - - - - - org.netbeans.modules.db - - - - - org.netbeans.modules.db.metadata.model - - - - - org.netbeans.modules.editor.mimelookup - - - - org.netbeans.modules.editor.mimelookup.impl - - - - org.netbeans.modules.lexer - - - - - org.netbeans.modules.nbjunit - - - - - org.netbeans.modules.parsing.nb - - - - - - org.netbeans.modules.projectapi.nb - - - org.openide.util.lookup - - - - - - - com.sun.tools.odb - org.netbeans.modules.php.editor - org.netbeans.modules.db.sql.editor.api.completion - - - - + + + + org.netbeans.modules.apisupport.project + + + org.netbeans.modules.db.sql.editor + + + org.netbeans.modules.csl.api + + + + 2 + 2.27 + + + + org.netbeans.modules.csl.types + + + + 1 + 1.0 + + + + org.netbeans.modules.db + + + + 1 + + + + + org.netbeans.modules.db.core + + + + 1.0 + + + + org.netbeans.modules.db.metadata.model + + + + 0-1 + 0.8 + + + + org.netbeans.modules.dbapi + + + + 1.2 + + + + org.netbeans.modules.editor + + + + 3 + 1.53 + + + + org.netbeans.modules.editor.bracesmatching + + + + 0-1 + 1.22 + + + + org.netbeans.modules.editor.completion + + + + 1 + 1.12 + + + + org.netbeans.modules.editor.document + + + + 1.3 + + + + org.netbeans.modules.editor.fold + + + + 1 + 1.42 + + + + org.netbeans.modules.editor.lib + + + + 3 + 4.0 + + + + org.netbeans.modules.editor.lib2 + + + + 1 + 2.0 + + + + org.netbeans.modules.editor.mimelookup + + + + 1 + 1.26 + + + + org.netbeans.modules.lexer + + + + 2 + 1.27 + + + + org.netbeans.modules.projectapi + + + + 1 + 1.26 + + + + org.netbeans.modules.queries + + + + 1 + 1.15 + + + + org.netbeans.spi.editor.hints + + + + 0 + 1.53 + + + + org.netbeans.swing.plaf + + + + 1.34 + + + + org.openide.actions + + + + 6.2 + + + + org.openide.awt + + + + 6.7 + + + + org.openide.dialogs + + + + 6.2 + + + + org.openide.explorer + + + + 6.8 + + + + org.openide.filesystems + + + + 9.0 + + + + org.openide.loaders + + + + 7.61 + + + + org.openide.modules + + + + 6.2 + + + + org.openide.nodes + + + + 7.23 + + + + org.openide.text + + + + 6.16 + + + + org.openide.util + + + + 9.3 + + + + org.openide.util.lookup + + + + 8.0 + + + + org.openide.util.ui + + + + 9.3 + + + + + + unit + + org.netbeans.libs.junit4 + + + + org.netbeans.modules.csl.api + + + + + + org.netbeans.modules.db + + + + + org.netbeans.modules.db.metadata.model + + + + + org.netbeans.modules.editor.mimelookup + + + + org.netbeans.modules.editor.mimelookup.impl + + + + org.netbeans.modules.lexer + + + + + org.netbeans.modules.nbjunit + + + + + org.netbeans.modules.parsing.nb + + + + + + org.netbeans.modules.projectapi.nb + + + org.openide.util.lookup + + + + + + + com.sun.tools.odb + org.netbeans.modules.php.editor + org.netbeans.modules.db.sql.editor.api.completion + + + + diff --git a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/analyzer/SQLStatementAnalyzer.java b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/analyzer/SQLStatementAnalyzer.java index 4c17d2041285..155cc61f8100 100644 --- a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/analyzer/SQLStatementAnalyzer.java +++ b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/analyzer/SQLStatementAnalyzer.java @@ -238,9 +238,9 @@ protected QualIdent parseIdentifier() { } protected String getUnquotedIdentifier() { - // when quoter unavailable likely due to lack of connection + // quoter unavailable so returnas is if (quoter == null) { - return ""; + return seq.token().text().toString(); } return quoter.unquote(seq.token().text().toString()); } diff --git a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionProvider.java b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionProvider.java index 3b47b1cf4fe0..936a89353507 100644 --- a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionProvider.java +++ b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionProvider.java @@ -19,35 +19,19 @@ package org.netbeans.modules.db.sql.editor.completion; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import javax.swing.text.BadLocationException; import javax.swing.text.Document; import javax.swing.text.JTextComponent; -import org.netbeans.api.db.explorer.ConnectionManager; import org.netbeans.api.db.explorer.DatabaseConnection; -import org.netbeans.api.db.explorer.JDBCDriver; -import org.netbeans.api.db.explorer.JDBCDriverManager; import org.netbeans.api.lexer.Language; import org.netbeans.api.lexer.TokenHierarchy; import org.netbeans.api.lexer.TokenSequence; import org.netbeans.modules.db.api.sql.execute.SQLExecution; import org.netbeans.modules.db.sql.editor.ui.actions.SQLExecutionBaseAction; import org.netbeans.modules.db.sql.lexer.SQLTokenId; -import org.netbeans.modules.editor.NbEditorUtilities; import org.netbeans.spi.editor.completion.CompletionProvider; import org.netbeans.spi.editor.completion.CompletionTask; import org.netbeans.spi.editor.completion.support.AsyncCompletionTask; -import org.netbeans.spi.editor.hints.ChangeInfo; -import org.netbeans.spi.editor.hints.ErrorDescription; -import org.netbeans.spi.editor.hints.ErrorDescriptionFactory; -import org.netbeans.spi.editor.hints.Fix; -import org.netbeans.spi.editor.hints.HintsController; -import org.netbeans.spi.editor.hints.Severity; import org.openide.awt.StatusDisplayer; -import org.openide.text.Line; -import org.openide.util.Exceptions; import org.openide.util.Lookup; import org.openide.util.NbBundle; @@ -68,11 +52,7 @@ public CompletionTask createTask(int queryType, JTextComponent component) { /* to support DB related completion tasks (i.e. auto populating table names or db columns for given schema) check for connection */ DatabaseConnection dbconn = findDBConn(component); - // No database connection set or active - if (SQLCompletionProvider.dbconn == null) { - createSuggestions(component,dbconn); - } - + return new AsyncCompletionTask(new SQLCompletionQuery(dbconn), component); } @@ -95,7 +75,6 @@ public CompletionTask createTask(int queryType, JTextComponent component) { */ public int getAutoQueryTypes(JTextComponent component, String typedText) { // XXX: Check if "enable/disable" autocomplete is setting. See NETBEANS-188 - // If "." has not been typed then acceptable to start checking for options. if (!".".equals(typedText)) { // NOI18N return 0; @@ -110,7 +89,6 @@ public int getAutoQueryTypes(JTextComponent component, String typedText) { if (dbconn == null) { String message = NbBundle.getMessage(SQLCompletionProvider.class, "MSG_NoDatabaseConnection"); StatusDisplayer.getDefault().setStatusText(message); - createSuggestions(component, dbconn); SQLExecutionBaseAction.notifyNoDatabaseConnection(); } @@ -118,87 +96,12 @@ public int getAutoQueryTypes(JTextComponent component, String typedText) { if (dbconn != null && dbconn.getJDBCConnection() == null) { String message = NbBundle.getMessage(SQLCompletionProvider.class, "MSG_NotConnected"); StatusDisplayer.getDefault().setStatusText(message); - SQLExecutionBaseAction.notifyNoDatabaseConnection(); + SQLExecutionBaseAction.notifyNoDatabaseConnection(); // XXX: Maybe add content specific "fixs" } return COMPLETION_QUERY_TYPE; } - private void createSuggestions(JTextComponent component, DatabaseConnection dbconn) { - // setup hints and fixes for possible resolution to connection issue - List fixes = new ArrayList<>(Collections.emptyList()); - List warnings = new ArrayList<>(Collections.emptyList()); - - // determine the selected line - String selection = component.getSelectedText(); - Document doc = component.getDocument(); - - // for selected lines with content - if (selection != null && selection.length() > 0) { - // use NbEditorUtilities.getLine() to get line from current document and offset, - int lineOffset = component.getSelectionStart() - 1; - int endOffset = lineOffset + selection.length(); - - Line currentLine = NbEditorUtilities.getLine(doc, lineOffset, false); - - // setup sql hints/fixes - try { - // identify possible fixes - - // hint to create a new connection - fixes.add(new SqlNewConnectionFix()); - // hint to add a new driver for connection - fixes.add(new SqlNewDriveFix()); - // hint to correction connection - show dialog to do so - fixes.add(new SqlConnectFix(component)); - - // setup ErrorDescription and add to warnings - warnings.add( - ErrorDescriptionFactory.createErrorDescription( - Severity.WARNING, - "DB Connection Issue", - fixes, - doc, - doc.createPosition(lineOffset), - doc.createPosition(endOffset) - ) - ); - } catch (BadLocationException ex) { - Exceptions.printStackTrace(ex); - } - } else { - // for non-selected lines - - // setup sql hints/fixes - try { - // identify possible fixes - - // hint to create a new connection - fixes.add(new SqlNewConnectionFix()); - // hint to add a new driver for connection - fixes.add(new SqlNewDriveFix()); - // hint to correction connection - show dialog to do so - fixes.add(new SqlConnectFix(component)); - - // no line is selected so add to initial position - // setup ErrorDescription and add to warnings - warnings.add( - ErrorDescriptionFactory.createErrorDescription( - Severity.WARNING, - "DB Connection Issue", - fixes, - doc, - doc.createPosition(0), - doc.createPosition(0) - ) - ); - } catch (BadLocationException ex) { - Exceptions.printStackTrace(ex); - } - HintsController.setErrors(doc, SQL_CONNECTION_HINT_ID, warnings); - } - } - private static DatabaseConnection findDBConn(JTextComponent component) { Lookup context = findContext(component); if (context == null) { @@ -264,93 +167,4 @@ private static TokenSequence getSQLTokenSequence(Document doc) { TokenHierarchy hierarchy = TokenHierarchy.get(doc); return hierarchy.tokenSequence(SQLTokenId.language()); } - - private static class SqlNewConnectionFix implements Fix { - @Override - public String getText() { - return "Create New Database connection."; - } - - @Override - public ChangeInfo implement() throws Exception { - - // select given connection - ConnectionManager cm = ConnectionManager.getDefault(); - DatabaseConnection dbconn = findDBConn(component); - - JDBCDriver driver = null; - if (dbconn == null) { - // no connection, have to establish driver and related details - cm.showAddConnectionDialog(null); - } - ChangeInfo results = new ChangeInfo(); - - return results; - } - - private void setupDriver() { - JDBCDriverManager dm = JDBCDriverManager.getDefault(); - JDBCDriver[] drivers = dm.getDrivers(); - - if (drivers == null || drivers.length ==0) { - dm.showAddDriverDialog(); - } - } - - public SqlNewConnectionFix() { - } - public SqlNewConnectionFix(DatabaseConnection conn) { - } - } - - /** - * This case handles when driver and connections are available but not connected - */ - private static class SqlConnectFix implements Fix { - - @Override - public String getText() { - return "Connect to database"; - } - - @Override - public ChangeInfo implement() throws Exception { - - SQLExecutionBaseAction.notifyNoDatabaseConnection(); - ChangeInfo results = new ChangeInfo(); - return results; - } - - public SqlConnectFix(JTextComponent applicableComponent) { - component = applicableComponent; - } - public SqlConnectFix() { - } - } - - /** - * This case handles when driver and connections are available but not connected - */ - private static class SqlNewDriveFix implements Fix { - - @Override - public String getText() { - return "Add a New Database Driver"; - } - - @Override - public ChangeInfo implement() throws Exception { - ConnectionManager cm = ConnectionManager.getDefault(); - JDBCDriverManager dm = JDBCDriverManager.getDefault(); - dm.showAddDriverDialog(); - - ChangeInfo results = new ChangeInfo(); - return results; - } - - public SqlNewDriveFix() { - } - } } - - diff --git a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionQuery.java b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionQuery.java index 54548cb7d63e..a6f0dee6df61 100644 --- a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionQuery.java +++ b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionQuery.java @@ -57,6 +57,7 @@ import org.netbeans.modules.db.sql.analyzer.SQLStatementKind; import org.netbeans.modules.db.sql.analyzer.UpdateStatement; import org.netbeans.modules.db.sql.editor.api.completion.SQLCompletionResultSet; +import org.netbeans.modules.db.sql.editor.ui.actions.SQLExecutionBaseAction; import org.netbeans.modules.db.sql.lexer.SQLTokenId; import org.netbeans.spi.editor.completion.CompletionResultSet; import org.netbeans.spi.editor.completion.support.AsyncCompletionQuery; @@ -210,6 +211,7 @@ SQLCompletionItems doQuery(SQLCompletionEnv env, Metadata metadata, Quoter quote anchorOffset = ident.anchorOffset; substitutionOffset = ident.substitutionOffset; SQLStatementKind kind = statement.getKind(); + switch (kind) { case SELECT: completeSelect(); @@ -515,6 +517,7 @@ private void completeColumnSimpleIdent(String typedPrefix, boolean quoted) { if (tablesClause != null && !(tablesClause.getUnaliasedTableNames().isEmpty() && tablesClause.getAliasedTableNames().isEmpty())) { completeSimpleIdentBasedOnFromClause(typedPrefix, quoted); } else { + // have database metadata to populate if (metadata != null) { Schema defaultSchema = metadata.getDefaultSchema(); if (defaultSchema != null) { diff --git a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/resources/Bundle.properties b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/resources/Bundle.properties index 3815692f9a89..e9f4f33c5d62 100644 --- a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/resources/Bundle.properties +++ b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/resources/Bundle.properties @@ -40,5 +40,3 @@ sql-double-literal=Floating Point sql-keyword=Keyword sql-errors=Error sql-dot=Period - -LAB_db_sql_editor_annotation_warn="Select Connection from the combo box at the top of the SQL Editor window." From 11150b7840d6a4e8e6273a79cacd46f6b6044e94 Mon Sep 17 00:00:00 2001 From: Eric Bresie Date: Sat, 20 Mar 2021 13:05:44 -0500 Subject: [PATCH 14/16] Allows auto-completion even with no connection. --- .../completion/SQLCompletionProvider.java | 4 +-- .../editor/completion/SQLCompletionQuery.java | 6 ++-- .../modules/db/sql/editor/resources/layer.xml | 2 +- ...s-modules-db-sql-editor_annotation.xml.xml | 34 +++++++++++++++++++ 4 files changed, 40 insertions(+), 6 deletions(-) create mode 100644 ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/resources/org-netbeans-modules-db-sql-editor_annotation.xml.xml diff --git a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionProvider.java b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionProvider.java index 936a89353507..57bae87d6329 100644 --- a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionProvider.java +++ b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionProvider.java @@ -98,7 +98,7 @@ public int getAutoQueryTypes(JTextComponent component, String typedText) { StatusDisplayer.getDefault().setStatusText(message); SQLExecutionBaseAction.notifyNoDatabaseConnection(); // XXX: Maybe add content specific "fixs" - } + } return COMPLETION_QUERY_TYPE; } @@ -167,4 +167,4 @@ private static TokenSequence getSQLTokenSequence(Document doc) { TokenHierarchy hierarchy = TokenHierarchy.get(doc); return hierarchy.tokenSequence(SQLTokenId.language()); } -} + } diff --git a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionQuery.java b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionQuery.java index a6f0dee6df61..51a47122dde4 100644 --- a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionQuery.java +++ b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionQuery.java @@ -153,7 +153,7 @@ public void run(Metadata metadata) { } } }); - } else { + } else { // No DB Connection established presently doQuery(newEnv, metadata, quoter); } @@ -1062,9 +1062,9 @@ private Identifier createIdentifier(List parts, boolean incomplete, int quoted = true; } else if (quoteString.length() > 0 && lastPrefix.endsWith(quoteString)) { // User typed '"foo".bar"|', can't complete. - return null; + return null; + } } - } for (int i = 0; i < parts.size(); i++) { String unquoted = quoter.unquote(parts.get(i)); if (unquoted.length() == 0) { diff --git a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/resources/layer.xml b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/resources/layer.xml index 7257cdcdf705..03b8a4b9e730 100644 --- a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/resources/layer.xml +++ b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/resources/layer.xml @@ -148,9 +148,9 @@ + - diff --git a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/resources/org-netbeans-modules-db-sql-editor_annotation.xml.xml b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/resources/org-netbeans-modules-db-sql-editor_annotation.xml.xml new file mode 100644 index 000000000000..cfa3cffe6883 --- /dev/null +++ b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/resources/org-netbeans-modules-db-sql-editor_annotation.xml.xml @@ -0,0 +1,34 @@ + + + + \ No newline at end of file From a036c0e7c7040b29465d1bd9894b5e6e752d7fdd Mon Sep 17 00:00:00 2001 From: Eric Bresie Date: Sat, 3 Apr 2021 10:26:25 -0500 Subject: [PATCH 15/16] Updates based on PR comments. Removed "annotation" and related items associated with them. --- ...s-modules-db-sql-editor_annotation.xml.xml | 34 ------------------- 1 file changed, 34 deletions(-) delete mode 100644 ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/resources/org-netbeans-modules-db-sql-editor_annotation.xml.xml diff --git a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/resources/org-netbeans-modules-db-sql-editor_annotation.xml.xml b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/resources/org-netbeans-modules-db-sql-editor_annotation.xml.xml deleted file mode 100644 index cfa3cffe6883..000000000000 --- a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/resources/org-netbeans-modules-db-sql-editor_annotation.xml.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - \ No newline at end of file From 4be31d45b955db29e90a7463f455c36cf76058dd Mon Sep 17 00:00:00 2001 From: Eric Bresie Date: Fri, 16 Jul 2021 10:27:08 -0500 Subject: [PATCH 16/16] Update SQLCompletionProvider.java Removed unused variables including hint variable --- .../db/sql/editor/completion/SQLCompletionProvider.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionProvider.java b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionProvider.java index 57bae87d6329..8659c6fe0bf9 100644 --- a/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionProvider.java +++ b/ide/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionProvider.java @@ -40,10 +40,6 @@ * @author Andrei Badea */ public class SQLCompletionProvider implements CompletionProvider { - private static final String SQL_CONNECTION_HINT_ID = "sql_connection_hint"; - private static JTextComponent component = null; - private static DatabaseConnection dbconn = null; - @Override public CompletionTask createTask(int queryType, JTextComponent component) { if (queryType == CompletionProvider.COMPLETION_QUERY_TYPE || @@ -167,4 +163,4 @@ private static TokenSequence getSQLTokenSequence(Document doc) { TokenHierarchy hierarchy = TokenHierarchy.get(doc); return hierarchy.tokenSequence(SQLTokenId.language()); } - } +}