diff --git a/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionItems.java b/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionItems.java --- a/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionItems.java +++ b/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionItems.java @@ -69,51 +69,51 @@ this.itemOffset = itemOffset; } - public Set addSchemas(Catalog catalog, Set restrict, String prefix, final String quoteString, final int substitutionOffset) { + public Set addSchemas(Catalog catalog, Set restrict, String prefix, final boolean quote, final int substitutionOffset) { Set result = new TreeSet(); filterMetadata(catalog.getSchemas(), restrict, prefix, new Handler() { public void handle(Schema schema) { if (!schema.isSynthetic()) { String schemaName = schema.getName(); - items.add(SQLCompletionItem.schema(schemaName, quote(schemaName, quoteString), itemOffset + substitutionOffset)); + items.add(SQLCompletionItem.schema(schemaName, doQuote(schemaName, quote), itemOffset + substitutionOffset)); } } }); return result; } - public void addTables(Schema schema, Set restrict, String prefix, final String quoteString, final int substitutionOffset) { + public void addTables(Schema schema, Set restrict, String prefix, final boolean quote, final int substitutionOffset) { filterMetadata(schema.getTables(), restrict, prefix, new Handler() { public void handle(Table table) { String tableName = table.getName(); - items.add(SQLCompletionItem.table(tableName, quote(tableName, quoteString), itemOffset + substitutionOffset)); + items.add(SQLCompletionItem.table(tableName, doQuote(tableName, quote), itemOffset + substitutionOffset)); } }); } - public void addAliases(List aliases, String prefix, final String quoteString, final int substitutionOffset) { + public void addAliases(List aliases, String prefix, final boolean quote, final int substitutionOffset) { filterStrings(aliases, null, prefix, new Handler() { public void handle(String alias) { - items.add(SQLCompletionItem.alias(alias, alias, itemOffset + substitutionOffset)); + items.add(SQLCompletionItem.alias(alias, doQuote(alias, quote), itemOffset + substitutionOffset)); } }); } - public void addColumns(Schema schema, final Table table, String prefix, final String quoteString, final int substitutionOffset) { + public void addColumns(Schema schema, final Table table, String prefix, final boolean quote, final int substitutionOffset) { final QualIdent qualTableName = schema.isDefault() ? null : new QualIdent(schema.getName(), table.getName()); filterMetadata(table.getColumns(), null, prefix, new Handler() { public void handle(Column column) { String columnName = column.getName(); if (qualTableName != null) { - items.add(SQLCompletionItem.column(qualTableName, columnName, quote(columnName, quoteString), itemOffset + substitutionOffset)); + items.add(SQLCompletionItem.column(qualTableName, columnName, doQuote(columnName, quote), itemOffset + substitutionOffset)); } else { - items.add(SQLCompletionItem.column(table.getName(), columnName, quote(columnName, quoteString), itemOffset + substitutionOffset)); + items.add(SQLCompletionItem.column(table.getName(), columnName, doQuote(columnName, quote), itemOffset + substitutionOffset)); } } }); } - public void addColumns(Catalog catalog, QualIdent tableName, String prefix, final String quoteString, final int substitutionOffset) { + public void addColumns(Catalog catalog, QualIdent tableName, String prefix, final boolean quote, final int substitutionOffset) { Schema schema = null; Table table = null; if (tableName.isSimple()) { @@ -133,7 +133,7 @@ table = schema.getTable(tableName.getSimpleName()); } if (table != null) { - addColumns(schema, table, prefix, quoteString, substitutionOffset); + addColumns(schema, table, prefix, quote, substitutionOffset); } } @@ -145,9 +145,9 @@ return items.iterator(); } - private String quote(String identifier, String quoteString) { - if (quoteString != null) { - return new StringBuilder(identifier.length() + 2).append(quoteString).append(identifier).append(quoteString).toString(); + private String doQuote(String identifier, boolean always) { + if (always) { + return quoter.quoteAlways(identifier); } else { return quoter.quoteIfNeeded(identifier); } diff --git a/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionQuery.java b/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionQuery.java --- a/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionQuery.java +++ b/db.sql.editor/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionQuery.java @@ -90,8 +90,8 @@ private final DatabaseConnection dbconn; private Metadata metadata; - private String quoteString; private SQLCompletionEnv env; + private Quoter quoter; private FromClause fromClause; private int anchorOffset = -1; // Relative to statement offset. private int substitutionOffset = 0; // Relative to statement offset. @@ -111,16 +111,14 @@ if (conn == null) { return; } - String identifierQuoteString = null; Quoter quoter = null; try { DatabaseMetaData dmd = conn.getMetaData(); - identifierQuoteString = dmd.getIdentifierQuoteString(); quoter = SQLIdentifiers.createQuoter(dmd); } catch (SQLException e) { throw new RuntimeException(e); } - doQuery(newEnv, metadata, quoter, identifierQuoteString); + doQuery(newEnv, metadata, quoter); } }); } catch (MetadataModelException e) { @@ -136,10 +134,10 @@ } // Called by unit tests. - SQLCompletionItems doQuery(SQLCompletionEnv env, Metadata metadata, Quoter quoter, String quoteString) { + SQLCompletionItems doQuery(SQLCompletionEnv env, Metadata metadata, Quoter quoter) { this.env = env; this.metadata = metadata; - this.quoteString = quoteString; + this.quoter = quoter; anchorOffset = -1; substitutionOffset = 0; if (env != null && env.isSelect()) { @@ -182,45 +180,45 @@ private void insideSelect(Identifier ident) { if (ident.fullyTypedIdent.isEmpty()) { - completeSelectSimpleIdent(ident.lastPrefix, ident.prefixQuoteString); + completeSelectSimpleIdent(ident.lastPrefix, ident.quoted); } else if (ident.fullyTypedIdent.isSimple()) { - completeSelectSingleQualIdent(ident.fullyTypedIdent, ident.lastPrefix, ident.prefixQuoteString); + completeSelectSingleQualIdent(ident.fullyTypedIdent, ident.lastPrefix, ident.quoted); } else if (ident.fullyTypedIdent.isSingleQualified()) { - completeSelectDoubleQualIdent(ident.fullyTypedIdent, ident.lastPrefix, ident.prefixQuoteString); + completeSelectDoubleQualIdent(ident.fullyTypedIdent, ident.lastPrefix, ident.quoted); } } private void insideFrom(Identifier ident) { if (ident.fullyTypedIdent.isEmpty()) { - completeFromSimpleIdent(ident.lastPrefix, ident.prefixQuoteString); + completeFromSimpleIdent(ident.lastPrefix, ident.quoted); } else if (ident.fullyTypedIdent.isSimple()) { - completeFromSingleQualIdent(ident.fullyTypedIdent, ident.lastPrefix, ident.prefixQuoteString); + completeFromSingleQualIdent(ident.fullyTypedIdent, ident.lastPrefix, ident.quoted); } } private void insideJoinCondition(Identifier ident) { if (ident.fullyTypedIdent.isEmpty()) { - completeSimpleIdentBasedOnFromClause(ident.lastPrefix, ident.prefixQuoteString); + completeSimpleIdentBasedOnFromClause(ident.lastPrefix, ident.quoted); } else if (ident.fullyTypedIdent.isSimple()) { - completeSingleQualIdentBasedOnFromClause(ident.fullyTypedIdent, ident.lastPrefix, ident.prefixQuoteString); + completeSingleQualIdentBasedOnFromClause(ident.fullyTypedIdent, ident.lastPrefix, ident.quoted); } else if (ident.fullyTypedIdent.isSingleQualified()) { - completeDoubleQualIdentBasedOnFromClause(ident.fullyTypedIdent, ident.lastPrefix, ident.prefixQuoteString); + completeDoubleQualIdentBasedOnFromClause(ident.fullyTypedIdent, ident.lastPrefix, ident.quoted); } } private void insideWhere(Identifier ident) { if (ident.fullyTypedIdent.isEmpty()) { - completeSimpleIdentBasedOnFromClause(ident.lastPrefix, ident.prefixQuoteString); + completeSimpleIdentBasedOnFromClause(ident.lastPrefix, ident.quoted); } else if (ident.fullyTypedIdent.isSimple()) { - completeSingleQualIdentBasedOnFromClause(ident.fullyTypedIdent, ident.lastPrefix, ident.prefixQuoteString); + completeSingleQualIdentBasedOnFromClause(ident.fullyTypedIdent, ident.lastPrefix, ident.quoted); } else if (ident.fullyTypedIdent.isSingleQualified()) { - completeDoubleQualIdentBasedOnFromClause(ident.fullyTypedIdent, ident.lastPrefix, ident.prefixQuoteString); + completeDoubleQualIdentBasedOnFromClause(ident.fullyTypedIdent, ident.lastPrefix, ident.quoted); } } - private void completeSelectSimpleIdent(String typedPrefix, String prefixQuoteString) { + private void completeSelectSimpleIdent(String typedPrefix, boolean quoted) { if (fromClause != null) { - completeSimpleIdentBasedOnFromClause(typedPrefix, prefixQuoteString); + completeSimpleIdentBasedOnFromClause(typedPrefix, quoted); } else { Catalog defaultCatalog = metadata.getDefaultCatalog(); Schema defaultSchema = metadata.getDefaultCatalog().getDefaultSchema(); @@ -229,20 +227,20 @@ // would be too many columns. if (typedPrefix != null) { for (Table table : defaultSchema.getTables()) { - items.addColumns(defaultSchema, table, typedPrefix, prefixQuoteString, substitutionOffset); + items.addColumns(defaultSchema, table, typedPrefix, quoted, substitutionOffset); } } // All tables in default schema. - items.addTables(defaultSchema, null, typedPrefix, prefixQuoteString, substitutionOffset); + items.addTables(defaultSchema, null, typedPrefix, quoted, substitutionOffset); // All schemas. - items.addSchemas(defaultCatalog, null, typedPrefix, prefixQuoteString, substitutionOffset); + items.addSchemas(defaultCatalog, null, typedPrefix, quoted, substitutionOffset); } } } - private void completeSelectSingleQualIdent(QualIdent fullyTypedIdent, String lastPrefix, String prefixQuoteString) { + private void completeSelectSingleQualIdent(QualIdent fullyTypedIdent, String lastPrefix, boolean quoted) { if (fromClause != null) { - completeSingleQualIdentBasedOnFromClause(fullyTypedIdent, lastPrefix, prefixQuoteString); + completeSingleQualIdentBasedOnFromClause(fullyTypedIdent, lastPrefix, quoted); } else { Catalog defaultCatalog = metadata.getDefaultCatalog(); Schema defaultSchema = defaultCatalog.getDefaultSchema(); @@ -250,43 +248,43 @@ // All columns in the typed table. Table table = defaultSchema.getTable(fullyTypedIdent.getSimpleName()); if (table != null) { - items.addColumns(defaultSchema, table, lastPrefix, prefixQuoteString, substitutionOffset); + items.addColumns(defaultSchema, table, lastPrefix, quoted, substitutionOffset); } // All tables in the typed schema. Schema schema = defaultCatalog.getSchema(fullyTypedIdent.getSimpleName()); if (schema != null) { - items.addTables(schema, null, lastPrefix, prefixQuoteString, substitutionOffset); + items.addTables(schema, null, lastPrefix, quoted, substitutionOffset); } } } } - private void completeSelectDoubleQualIdent(QualIdent fullyTypedIdent, String lastPrefix, String prefixQuoteString) { + private void completeSelectDoubleQualIdent(QualIdent fullyTypedIdent, String lastPrefix, boolean quoted) { if (fromClause != null) { - completeDoubleQualIdentBasedOnFromClause(fullyTypedIdent, lastPrefix, prefixQuoteString); + completeDoubleQualIdentBasedOnFromClause(fullyTypedIdent, lastPrefix, quoted); } else { - items.addColumns(metadata.getDefaultCatalog(), fullyTypedIdent, lastPrefix, prefixQuoteString, substitutionOffset); + items.addColumns(metadata.getDefaultCatalog(), fullyTypedIdent, lastPrefix, quoted, substitutionOffset); } } - private void completeFromSimpleIdent(String typedPrefix, String prefixQuoteString) { + private void completeFromSimpleIdent(String typedPrefix, boolean quoted) { Catalog defaultCatalog = metadata.getDefaultCatalog(); Schema schema = defaultCatalog.getDefaultSchema(); if (schema != null) { - items.addTables(schema, null, typedPrefix, prefixQuoteString, substitutionOffset); + items.addTables(schema, null, typedPrefix, quoted, substitutionOffset); } // All schemas. - items.addSchemas(defaultCatalog, null, typedPrefix, prefixQuoteString, substitutionOffset); + items.addSchemas(defaultCatalog, null, typedPrefix, quoted, substitutionOffset); } - private void completeFromSingleQualIdent(QualIdent fullyTypedIdent, String lastPrefix, String prefixQuoteString) { + private void completeFromSingleQualIdent(QualIdent fullyTypedIdent, String lastPrefix, boolean quoted) { Schema schema = metadata.getDefaultCatalog().getSchema(fullyTypedIdent.getSimpleName()); if (schema != null) { - items.addTables(schema, null, lastPrefix, prefixQuoteString, substitutionOffset); + items.addTables(schema, null, lastPrefix, quoted, substitutionOffset); } } - private void completeSimpleIdentBasedOnFromClause(String typedPrefix, String prefixQuoteString) { + private void completeSimpleIdentBasedOnFromClause(String typedPrefix, boolean quoted) { assert fromClause != null; // Columns from tables and aliases. Set tableNames = fromClause.getUnaliasedTableNames(); @@ -297,7 +295,7 @@ } Catalog defaultCatalog = metadata.getDefaultCatalog(); for (QualIdent tableName : allTableNames) { - items.addColumns(defaultCatalog, tableName, typedPrefix, prefixQuoteString, substitutionOffset); + items.addColumns(defaultCatalog, tableName, typedPrefix, quoted, substitutionOffset); } Schema defaultSchema = defaultCatalog.getDefaultSchema(); // Tables from default schema, restricted to those already in the FROM clause. @@ -314,12 +312,12 @@ } } } - items.addTables(defaultSchema, simpleTableNames, typedPrefix, prefixQuoteString, substitutionOffset); + items.addTables(defaultSchema, simpleTableNames, typedPrefix, quoted, substitutionOffset); } // Aliases. List sortedAliases = new ArrayList(aliases.keySet()); Collections.sort(sortedAliases); - items.addAliases(sortedAliases, typedPrefix, prefixQuoteString, substitutionOffset); + items.addAliases(sortedAliases, typedPrefix, quoted, substitutionOffset); // Schemas based on qualified tables. Set schemaNames = new HashSet(); for (QualIdent tableName : tableNames) { @@ -327,10 +325,10 @@ schemaNames.add(tableName.getFirstQualifier()); } } - items.addSchemas(defaultCatalog, schemaNames, typedPrefix, prefixQuoteString, substitutionOffset); + items.addSchemas(defaultCatalog, schemaNames, typedPrefix, quoted, substitutionOffset); } - private void completeSingleQualIdentBasedOnFromClause(QualIdent fullyTypedIdent, String lastPrefix, String prefixQuoteString) { + private void completeSingleQualIdentBasedOnFromClause(QualIdent fullyTypedIdent, String lastPrefix, boolean quoted) { assert fromClause != null; Catalog defaultCatalog = metadata.getDefaultCatalog(); // Assume table name. It must be in the FROM clause either as a simple name, or qualified by the default schema. @@ -348,7 +346,7 @@ tableName = fromClause.getTableNameByAlias(alias); } if (tableName != null) { - items.addColumns(defaultCatalog, tableName, lastPrefix, prefixQuoteString,substitutionOffset); + items.addColumns(defaultCatalog, tableName, lastPrefix, quoted,substitutionOffset); } // Now assume schema name. Schema schema = defaultCatalog.getSchema(fullyTypedIdent.getSimpleName()); @@ -360,14 +358,14 @@ tableNames.add(unaliasedTableName.getSimpleName()); } } - items.addTables(schema, tableNames, lastPrefix, prefixQuoteString, substitutionOffset); + items.addTables(schema, tableNames, lastPrefix, quoted, substitutionOffset); } } - private void completeDoubleQualIdentBasedOnFromClause(QualIdent fullyTypedIdent, String lastPrefix, String prefixQuoteString) { + private void completeDoubleQualIdentBasedOnFromClause(QualIdent fullyTypedIdent, String lastPrefix, boolean quoted) { assert fromClause != null; if (fromClause.getUnaliasedTableNames().contains(fullyTypedIdent)) { - items.addColumns(metadata.getDefaultCatalog(), fullyTypedIdent, lastPrefix, prefixQuoteString, substitutionOffset); + items.addColumns(metadata.getDefaultCatalog(), fullyTypedIdent, lastPrefix, quoted, substitutionOffset); } } @@ -462,7 +460,7 @@ */ private Identifier createIdentifier(List parts, boolean incomplete, int lastPrefixOffset) { String lastPrefix = null; - String prefixQuoteString = null; + boolean quoted = false; int substOffset = lastPrefixOffset; if (parts.isEmpty()) { if (incomplete) { @@ -473,65 +471,31 @@ } else { if (!incomplete) { lastPrefix = parts.remove(parts.size() - 1); - if (quoteString != null) { - if (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 = unquote(lastPrefix, quoteString); - if (lastPrefix != null) { - lastPrefixOffset = lastPrefixOffset + (lastPrefixLength - lastPrefix.length()); - } else { - lastPrefixOffset = lastPrefixOffset + lastPrefixLength; - } - prefixQuoteString = quoteString; - } else if (lastPrefix.endsWith(quoteString)) { - // User typed '"foo".bar"|', can't complete. + String quoteString = quoter.getQuoteString(); + if (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 (lastPrefix.endsWith(quoteString)) { + // User typed '"foo".bar"|', can't complete. + return null; } } for (int i = 0; i < parts.size(); i++) { - String unquoted = unquote(parts.get(i), quoteString); - if (unquoted == null) { + String unquoted = quoter.unquote(parts.get(i)); + if (unquoted.length() == 0) { // User typed something like '"foo".""."bar|'. return null; } parts.set(i, unquoted); } } - return new Identifier(new QualIdent(parts), lastPrefix, prefixQuoteString, lastPrefixOffset, substOffset); - } - - static String unquote(String identifier, String quote) { - if (quote == null) { - return identifier; - } - int start = 0; - while (identifier.regionMatches(start, quote, 0, quote.length())) { - start += quote.length(); - } - int end = identifier.length(); - if (end > start) { - for (;;) { - int offset = end - quote.length(); - if (identifier.regionMatches(offset, quote, 0, quote.length())) { - end = offset; - } else { - break; - } - } - } - String result = null; - if (start < end) { - result = identifier.substring(start, end); - if (result.length() == 0) { - result = null; - } - } - return result; + return new Identifier(new QualIdent(parts), lastPrefix, quoted, lastPrefixOffset, substOffset); } private static void reportError(MetadataModelException e) { @@ -550,14 +514,14 @@ final QualIdent fullyTypedIdent; final String lastPrefix; - final String prefixQuoteString; + final boolean quoted; final int anchorOffset; final int substitutionOffset; - private Identifier(QualIdent fullyTypedIdent, String lastPrefix, String prefixQuoteString, int anchorOffset, int substitutionOffset) { + private Identifier(QualIdent fullyTypedIdent, String lastPrefix, boolean quoted, int anchorOffset, int substitutionOffset) { this.fullyTypedIdent = fullyTypedIdent; this.lastPrefix = lastPrefix; - this.prefixQuoteString = prefixQuoteString; + this.quoted = quoted; this.anchorOffset = anchorOffset; this.substitutionOffset = substitutionOffset; } diff --git a/db.sql.editor/test/unit/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionQueryUtilsTest.java b/db.sql.editor/test/unit/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionQueryUtilsTest.java deleted file mode 100644 --- a/db.sql.editor/test/unit/src/org/netbeans/modules/db/sql/editor/completion/SQLCompletionQueryUtilsTest.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * - * The contents of this file are subject to the terms of either the GNU - * General Public License Version 2 only ("GPL") or the Common - * Development and Distribution License("CDDL") (collectively, the - * "License"). You may not use this file except in compliance with the - * License. You can obtain a copy of the License at - * http://www.netbeans.org/cddl-gplv2.html - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the - * specific language governing permissions and limitations under the - * License. When distributing the software, include this License Header - * Notice in each file and include the License file at - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this - * particular file as subject to the "Classpath" exception as provided - * by Sun in the GPL Version 2 section of the License file that - * accompanied this code. If applicable, add the following below the - * License Header, with the fields enclosed by brackets [] replaced by - * your own identifying information: - * "Portions Copyrighted [year] [name of copyright owner]" - * - * If you wish your version of this file to be governed by only the CDDL - * or only the GPL Version 2, indicate your decision by adding - * "[Contributor] elects to include this software in this distribution - * under the [CDDL or GPL Version 2] license." If you do not indicate a - * single choice of license, a recipient has the option to distribute - * your version of this file under either the CDDL, the GPL Version 2 or - * to extend the choice of license to its licensees as provided above. - * However, if you add GPL Version 2 code and therefore, elected the GPL - * Version 2 license, then the option applies only if the new code is - * made subject to such option by the copyright holder. - * - * Contributor(s): - * - * Portions Copyrighted 2008 Sun Microsystems, Inc. - */ - -package org.netbeans.modules.db.sql.editor.completion; - -import org.netbeans.junit.NbTestCase; - -/** - * - * @author Andrei Badea - */ -public class SQLCompletionQueryUtilsTest extends NbTestCase { - - public SQLCompletionQueryUtilsTest(String name) { - super(name); - } - - public void testUnquote() { - assertEquals("id", SQLCompletionQuery.unquote("id", null)); - assertEquals("id", SQLCompletionQuery.unquote("id", "`")); - assertEquals("id", SQLCompletionQuery.unquote("id", "`")); - assertEquals("id", SQLCompletionQuery.unquote("id", "`")); - assertEquals("id", SQLCompletionQuery.unquote("id", "`")); - assertEquals("id", SQLCompletionQuery.unquote("id", "`")); - assertNull(SQLCompletionQuery.unquote("``", "`")); - assertNull(SQLCompletionQuery.unquote("```", "`")); - } -}