Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id 6274A200D3D for ; Mon, 13 Nov 2017 10:51:59 +0100 (CET) Received: by cust-asf.ponee.io (Postfix) id 60E6C160C15; Mon, 13 Nov 2017 09:51:59 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id B7039160BE4 for ; Mon, 13 Nov 2017 10:51:57 +0100 (CET) Received: (qmail 41275 invoked by uid 500); 13 Nov 2017 09:51:56 -0000 Mailing-List: contact commits-help@ignite.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@ignite.apache.org Delivered-To: mailing list commits@ignite.apache.org Received: (qmail 41207 invoked by uid 99); 13 Nov 2017 09:51:56 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 13 Nov 2017 09:51:56 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id E2B81DFE85; Mon, 13 Nov 2017 09:51:55 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: sboikov@apache.org To: commits@ignite.apache.org Date: Mon, 13 Nov 2017 09:51:58 -0000 Message-Id: <80c6b439eb1e4a91ad825b921ef90730@git.apache.org> In-Reply-To: <7fe468c3a1934aaeaa8a26f0e695af20@git.apache.org> References: <7fe468c3a1934aaeaa8a26f0e695af20@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [04/28] ignite git commit: IGNITE-6848: SQL parser: support DROP INDEX command. This closes #3006. archived-at: Mon, 13 Nov 2017 09:51:59 -0000 IGNITE-6848: SQL parser: support DROP INDEX command. This closes #3006. Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/a1b6a33f Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/a1b6a33f Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/a1b6a33f Branch: refs/heads/ignite-zk Commit: a1b6a33ff16b927e9c5b232a70af20f03f9b36c0 Parents: 145c59d Author: devozerov Authored: Thu Nov 9 14:37:54 2017 +0300 Committer: devozerov Committed: Thu Nov 9 14:37:54 2017 +0300 ---------------------------------------------------------------------- .../apache/ignite/internal/sql/SqlLexer.java | 6 + .../apache/ignite/internal/sql/SqlParser.java | 25 ++- .../ignite/internal/sql/SqlParserUtils.java | 9 +- .../sql/command/SqlDropIndexCommand.java | 80 ++++++++ .../internal/sql/SqlParserAbstractSelfTest.java | 46 +++++ .../sql/SqlParserCreateIndexSelfTest.java | 178 +++++++++++++++++ .../sql/SqlParserDropIndexSelfTest.java | 99 ++++++++++ .../ignite/internal/sql/SqlParserSelfTest.java | 198 ------------------- .../processors/query/h2/IgniteH2Indexing.java | 5 +- .../query/h2/ddl/DdlStatementsProcessor.java | 20 +- .../IgniteCacheQuerySelfTestSuite.java | 6 +- 11 files changed, 452 insertions(+), 220 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/a1b6a33f/modules/core/src/main/java/org/apache/ignite/internal/sql/SqlLexer.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/sql/SqlLexer.java b/modules/core/src/main/java/org/apache/ignite/internal/sql/SqlLexer.java index a8009b7..3fd6fa9 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/sql/SqlLexer.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/sql/SqlLexer.java @@ -176,6 +176,10 @@ public class SqlLexer implements SqlLexerToken { } } + token = null; + tokenPos = pos; + tokenTyp = SqlLexerTokenType.EOF; + return false; } @@ -191,6 +195,8 @@ public class SqlLexer implements SqlLexerToken { /** {@inheritDoc} */ public char tokenFirstChar() { + assert tokenTyp != SqlLexerTokenType.EOF; + return token.charAt(0); } http://git-wip-us.apache.org/repos/asf/ignite/blob/a1b6a33f/modules/core/src/main/java/org/apache/ignite/internal/sql/SqlParser.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/sql/SqlParser.java b/modules/core/src/main/java/org/apache/ignite/internal/sql/SqlParser.java index 9e0eee0..19f526d 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/sql/SqlParser.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/sql/SqlParser.java @@ -19,6 +19,7 @@ package org.apache.ignite.internal.sql; import org.apache.ignite.internal.sql.command.SqlCommand; import org.apache.ignite.internal.sql.command.SqlCreateIndexCommand; +import org.apache.ignite.internal.sql.command.SqlDropIndexCommand; import org.jetbrains.annotations.Nullable; import static org.apache.ignite.internal.sql.SqlKeyword.CREATE; @@ -27,10 +28,8 @@ import static org.apache.ignite.internal.sql.SqlKeyword.HASH; import static org.apache.ignite.internal.sql.SqlKeyword.INDEX; import static org.apache.ignite.internal.sql.SqlKeyword.PRIMARY; import static org.apache.ignite.internal.sql.SqlKeyword.SPATIAL; -import static org.apache.ignite.internal.sql.SqlKeyword.TABLE; import static org.apache.ignite.internal.sql.SqlKeyword.UNIQUE; import static org.apache.ignite.internal.sql.SqlParserUtils.errorUnexpectedToken; -import static org.apache.ignite.internal.sql.SqlParserUtils.errorUnsupported; import static org.apache.ignite.internal.sql.SqlParserUtils.errorUnsupportedIfMatchesKeyword; import static org.apache.ignite.internal.sql.SqlParserUtils.matchesKeyword; @@ -139,9 +138,6 @@ public class SqlParser { break; - case TABLE: - throw errorUnsupported(lex); - case SPATIAL: if (lex.shift() && matchesKeyword(lex, INDEX)) cmd = new SqlCreateIndexCommand().spatial(true); @@ -157,7 +153,7 @@ public class SqlParser { errorUnsupportedIfMatchesKeyword(lex, HASH, PRIMARY, UNIQUE); } - throw errorUnexpectedToken(lex, INDEX, TABLE, SPATIAL); + throw errorUnexpectedToken(lex, INDEX, SPATIAL); } /** @@ -166,9 +162,20 @@ public class SqlParser { * @return Command. */ private SqlCommand processDrop() { - if (lex.shift() && lex.tokenType() == SqlLexerTokenType.DEFAULT) - throw errorUnsupported(lex); + if (lex.shift() && lex.tokenType() == SqlLexerTokenType.DEFAULT) { + SqlCommand cmd = null; + + switch (lex.token()) { + case INDEX: + cmd = new SqlDropIndexCommand(); + + break; + } + + if (cmd != null) + return cmd.parse(lex); + } - throw errorUnexpectedToken(lex, INDEX, TABLE); + throw errorUnexpectedToken(lex, INDEX); } } http://git-wip-us.apache.org/repos/asf/ignite/blob/a1b6a33f/modules/core/src/main/java/org/apache/ignite/internal/sql/SqlParserUtils.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/sql/SqlParserUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/sql/SqlParserUtils.java index cfe4b6f..2f3b3da 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/sql/SqlParserUtils.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/sql/SqlParserUtils.java @@ -163,14 +163,7 @@ public class SqlParserUtils { case DEFAULT: char c = token.tokenFirstChar(); - if ((c >= 'A' && c <= 'Z') || c == '_') { - if (SqlKeyword.isKeyword(token.token())) - throw errorUnexpectedToken(token, "[identifier]"); - - return true; - } - - throw error(token, "Illegal identifier name: " + token.token()); + return ((c >= 'A' && c <= 'Z') || c == '_') && !SqlKeyword.isKeyword(token.token()); case QUOTED: return true; http://git-wip-us.apache.org/repos/asf/ignite/blob/a1b6a33f/modules/core/src/main/java/org/apache/ignite/internal/sql/command/SqlDropIndexCommand.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/sql/command/SqlDropIndexCommand.java b/modules/core/src/main/java/org/apache/ignite/internal/sql/command/SqlDropIndexCommand.java new file mode 100644 index 0000000..1a1ea87 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/sql/command/SqlDropIndexCommand.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.internal.sql.command; + +import org.apache.ignite.internal.sql.SqlLexer; +import org.apache.ignite.internal.util.typedef.internal.S; + +import static org.apache.ignite.internal.sql.SqlKeyword.IF; +import static org.apache.ignite.internal.sql.SqlParserUtils.parseIfExists; +import static org.apache.ignite.internal.sql.SqlParserUtils.parseQualifiedIdentifier; + +/** + * DROP INDEX command. + */ +public class SqlDropIndexCommand implements SqlCommand { + /** Schema name. */ + private String schemaName; + + /** Index name. */ + private String idxName; + + /** IF EXISTS flag. */ + private boolean ifExists; + + /** {@inheritDoc} */ + @Override public String schemaName() { + return schemaName; + } + + /** {@inheritDoc} */ + @Override public void schemaName(String schemaName) { + this.schemaName = schemaName; + } + + /** + * @return Index name. + */ + public String indexName() { + return idxName; + } + + /** + * @return IF EXISTS flag. + */ + public boolean ifExists() { + return ifExists; + } + + /** {@inheritDoc} */ + @Override public SqlCommand parse(SqlLexer lex) { + ifExists = parseIfExists(lex); + + SqlQualifiedName idxQName = parseQualifiedIdentifier(lex, IF); + + schemaName = idxQName.schemaName(); + idxName = idxQName.name(); + + return this; + } + + /** {@inheritDoc} */ + @Override public String toString() { + return S.toString(SqlDropIndexCommand.class, this); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/a1b6a33f/modules/core/src/test/java/org/apache/ignite/internal/sql/SqlParserAbstractSelfTest.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/apache/ignite/internal/sql/SqlParserAbstractSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/sql/SqlParserAbstractSelfTest.java new file mode 100644 index 0000000..c095201 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/sql/SqlParserAbstractSelfTest.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.internal.sql; + +import org.apache.ignite.testframework.GridTestUtils; +import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; + +import java.util.concurrent.Callable; + +/** + * Common class for SQL parser tests. + */ +@SuppressWarnings("ThrowableNotThrown") +public abstract class SqlParserAbstractSelfTest extends GridCommonAbstractTest { + /** + * Make sure that parse error occurs. + * + * @param schema Schema. + * @param sql SQL. + * @param msg Expected error message. + */ + protected static void assertParseError(final String schema, final String sql, String msg) { + GridTestUtils.assertThrows(null, new Callable() { + @Override public Void call() throws Exception { + new SqlParser(schema, sql).nextCommand(); + + return null; + } + }, SqlParseException.class, msg); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/a1b6a33f/modules/core/src/test/java/org/apache/ignite/internal/sql/SqlParserCreateIndexSelfTest.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/apache/ignite/internal/sql/SqlParserCreateIndexSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/sql/SqlParserCreateIndexSelfTest.java new file mode 100644 index 0000000..5de0a3a --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/sql/SqlParserCreateIndexSelfTest.java @@ -0,0 +1,178 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.internal.sql; + +import org.apache.ignite.internal.sql.command.SqlCreateIndexCommand; +import org.apache.ignite.internal.sql.command.SqlIndexColumn; +import org.apache.ignite.internal.util.typedef.F; + +import java.util.Collection; +import java.util.Iterator; + +/** + * Tests for SQL parser: CREATE INDEX. + */ +@SuppressWarnings({"UnusedReturnValue", "ThrowableNotThrown"}) +public class SqlParserCreateIndexSelfTest extends SqlParserAbstractSelfTest { + /** + * Tests for CREATE INDEX command. + * + * @throws Exception If failed. + */ + public void testCreateIndex() throws Exception { + // Base. + parseValidate(null, "CREATE INDEX idx ON tbl(a)", null, "TBL", "IDX", "A", false); + parseValidate(null, "CREATE INDEX idx ON tbl(a ASC)", null, "TBL", "IDX", "A", false); + parseValidate(null, "CREATE INDEX idx ON tbl(a DESC)", null, "TBL", "IDX", "A", true); + + // Case (in)sensitivity. + parseValidate(null, "CREATE INDEX IDX ON TBL(COL)", null, "TBL", "IDX", "COL", false); + parseValidate(null, "CREATE INDEX iDx ON tBl(cOl)", null, "TBL", "IDX", "COL", false); + + parseValidate(null, "CREATE INDEX \"idx\" ON tbl(col)", null, "TBL", "idx", "COL", false); + parseValidate(null, "CREATE INDEX \"iDx\" ON tbl(col)", null, "TBL", "iDx", "COL", false); + + parseValidate(null, "CREATE INDEX idx ON \"tbl\"(col)", null, "tbl", "IDX", "COL", false); + parseValidate(null, "CREATE INDEX idx ON \"tBl\"(col)", null, "tBl", "IDX", "COL", false); + + parseValidate(null, "CREATE INDEX idx ON tbl(\"col\")", null, "TBL", "IDX", "col", false); + parseValidate(null, "CREATE INDEX idx ON tbl(\"cOl\")", null, "TBL", "IDX", "cOl", false); + + parseValidate(null, "CREATE INDEX idx ON tbl(\"cOl\" ASC)", null, "TBL", "IDX", "cOl", false); + parseValidate(null, "CREATE INDEX idx ON tbl(\"cOl\" DESC)", null, "TBL", "IDX", "cOl", true); + + // Columns. + parseValidate(null, "CREATE INDEX idx ON tbl(a, b)", null, "TBL", "IDX", "A", false, "B", false); + + parseValidate(null, "CREATE INDEX idx ON tbl(a ASC, b)", null, "TBL", "IDX", "A", false, "B", false); + parseValidate(null, "CREATE INDEX idx ON tbl(a, b ASC)", null, "TBL", "IDX", "A", false, "B", false); + parseValidate(null, "CREATE INDEX idx ON tbl(a ASC, b ASC)", null, "TBL", "IDX", "A", false, "B", false); + + parseValidate(null, "CREATE INDEX idx ON tbl(a DESC, b)", null, "TBL", "IDX", "A", true, "B", false); + parseValidate(null, "CREATE INDEX idx ON tbl(a, b DESC)", null, "TBL", "IDX", "A", false, "B", true); + parseValidate(null, "CREATE INDEX idx ON tbl(a DESC, b DESC)", null, "TBL", "IDX", "A", true, "B", true); + + parseValidate(null, "CREATE INDEX idx ON tbl(a ASC, b DESC)", null, "TBL", "IDX", "A", false, "B", true); + parseValidate(null, "CREATE INDEX idx ON tbl(a DESC, b ASC)", null, "TBL", "IDX", "A", true, "B", false); + + parseValidate(null, "CREATE INDEX idx ON tbl(a, b, c)", null, "TBL", "IDX", "A", false, "B", false, "C", false); + parseValidate(null, "CREATE INDEX idx ON tbl(a DESC, b, c)", null, "TBL", "IDX", "A", true, "B", false, "C", false); + parseValidate(null, "CREATE INDEX idx ON tbl(a, b DESC, c)", null, "TBL", "IDX", "A", false, "B", true, "C", false); + parseValidate(null, "CREATE INDEX idx ON tbl(a, b, c DESC)", null, "TBL", "IDX", "A", false, "B", false, "C", true); + + // Negative cases. + assertParseError(null, "CREATE INDEX idx ON tbl()", "Unexpected token"); + assertParseError(null, "CREATE INDEX idx ON tbl(a, a)", "Column already defined: A"); + assertParseError(null, "CREATE INDEX idx ON tbl(a, b, a)", "Column already defined: A"); + assertParseError(null, "CREATE INDEX idx ON tbl(b, a, a)", "Column already defined: A"); + + // Tests with schema. + parseValidate(null, "CREATE INDEX idx ON schema.tbl(a)", "SCHEMA", "TBL", "IDX", "A", false); + parseValidate(null, "CREATE INDEX idx ON \"schema\".tbl(a)", "schema", "TBL", "IDX", "A", false); + parseValidate(null, "CREATE INDEX idx ON \"sChema\".tbl(a)", "sChema", "TBL", "IDX", "A", false); + + parseValidate("SCHEMA", "CREATE INDEX idx ON tbl(a)", "SCHEMA", "TBL", "IDX", "A", false); + parseValidate("schema", "CREATE INDEX idx ON tbl(a)", "schema", "TBL", "IDX", "A", false); + parseValidate("sChema", "CREATE INDEX idx ON tbl(a)", "sChema", "TBL", "IDX", "A", false); + + // NOT EXISTS + SqlCreateIndexCommand cmd; + + cmd = parseValidate(null, "CREATE INDEX idx ON schema.tbl(a)", "SCHEMA", "TBL", "IDX", "A", false); + assertFalse(cmd.ifNotExists()); + + cmd = parseValidate(null, "CREATE INDEX IF NOT EXISTS idx ON schema.tbl(a)", "SCHEMA", "TBL", "IDX", "A", false); + assertTrue(cmd.ifNotExists()); + + assertParseError(null, "CREATE INDEX IF idx ON tbl(a)", "Unexpected token: \"IDX\""); + assertParseError(null, "CREATE INDEX IF NOT idx ON tbl(a)", "Unexpected token: \"IDX\""); + assertParseError(null, "CREATE INDEX IF EXISTS idx ON tbl(a)", "Unexpected token: \"EXISTS\""); + assertParseError(null, "CREATE INDEX NOT EXISTS idx ON tbl(a)", "Unexpected token: \"NOT\""); + + // SPATIAL + cmd = parseValidate(null, "CREATE INDEX idx ON schema.tbl(a)", "SCHEMA", "TBL", "IDX", "A", false); + assertFalse(cmd.spatial()); + + cmd = parseValidate(null, "CREATE SPATIAL INDEX idx ON schema.tbl(a)", "SCHEMA", "TBL", "IDX", "A", false); + assertTrue(cmd.spatial()); + + // UNIQUE + assertParseError(null, "CREATE UNIQUE INDEX idx ON tbl(a)", "Unsupported keyword: \"UNIQUE\""); + + // HASH + assertParseError(null, "CREATE HASH INDEX idx ON tbl(a)", "Unsupported keyword: \"HASH\""); + + // PRIMARY KEY + assertParseError(null, "CREATE PRIMARY KEY INDEX idx ON tbl(a)", "Unsupported keyword: \"PRIMARY\""); + } + + /** + * Parse and validate SQL script. + * + * @param schema Schema. + * @param sql SQL. + * @param expSchemaName Expected schema name. + * @param expTblName Expected table name. + * @param expIdxName Expected index name. + * @param expColDefs Expected column definitions. + * @return Command. + */ + private static SqlCreateIndexCommand parseValidate(String schema, String sql, String expSchemaName, + String expTblName, String expIdxName, Object... expColDefs) { + SqlCreateIndexCommand cmd = (SqlCreateIndexCommand)new SqlParser(schema, sql).nextCommand(); + + validate(cmd, expSchemaName, expTblName, expIdxName, expColDefs); + + return cmd; + } + + /** + * Validate create index command. + * + * @param cmd Command. + * @param expSchemaName Expected schema name. + * @param expTblName Expected table name. + * @param expIdxName Expected index name. + * @param expColDefs Expected column definitions. + */ + private static void validate(SqlCreateIndexCommand cmd, String expSchemaName, String expTblName, String expIdxName, + Object... expColDefs) { + assertEquals(expSchemaName, cmd.schemaName()); + assertEquals(expTblName, cmd.tableName()); + assertEquals(expIdxName, cmd.indexName()); + + if (F.isEmpty(expColDefs) || expColDefs.length % 2 == 1) + throw new IllegalArgumentException("Column definitions must be even."); + + Collection cols = cmd.columns(); + + assertEquals(expColDefs.length / 2, cols.size()); + + Iterator colIter = cols.iterator(); + + for (int i = 0; i < expColDefs.length;) { + SqlIndexColumn col = colIter.next(); + + String expColName = (String)expColDefs[i++]; + Boolean expDesc = (Boolean) expColDefs[i++]; + + assertEquals(expColName, col.name()); + assertEquals(expDesc, (Boolean)col.descending()); + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/a1b6a33f/modules/core/src/test/java/org/apache/ignite/internal/sql/SqlParserDropIndexSelfTest.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/apache/ignite/internal/sql/SqlParserDropIndexSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/sql/SqlParserDropIndexSelfTest.java new file mode 100644 index 0000000..a0af3a6 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/sql/SqlParserDropIndexSelfTest.java @@ -0,0 +1,99 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.internal.sql; + +import org.apache.ignite.internal.sql.command.SqlDropIndexCommand; + +/** + * Tests for SQL parser: CREATE INDEX. + */ +public class SqlParserDropIndexSelfTest extends SqlParserAbstractSelfTest { + /** + * Tests for DROP INDEX command. + * + * @throws Exception If failed. + */ + public void testDropIndex() throws Exception { + // Base. + parseValidate(null, "DROP INDEX idx", null, "IDX"); + parseValidate(null, "DROP INDEX IDX", null, "IDX"); + parseValidate(null, "DROP INDEX iDx", null, "IDX"); + + parseValidate(null, "DROP INDEX \"idx\"", null, "idx"); + parseValidate(null, "DROP INDEX \"IDX\"", null, "IDX"); + parseValidate(null, "DROP INDEX \"iDx\"", null, "iDx"); + + assertParseError(null, "DROP INDEX", "Unexpected"); + + // Schema. + parseValidate("SCHEMA", "DROP INDEX idx", "SCHEMA", "IDX"); + parseValidate("schema", "DROP INDEX idx", "schema", "IDX"); + parseValidate("sChema", "DROP INDEX idx", "sChema", "IDX"); + + parseValidate(null, "DROP INDEX \"SCHEMA\".idx", "SCHEMA", "IDX"); + parseValidate(null, "DROP INDEX \"schema\".idx", "schema", "IDX"); + parseValidate(null, "DROP INDEX \"sChema\".idx", "sChema", "IDX"); + + parseValidate(null, "DROP INDEX \"schema\".\"idx\"", "schema", "idx"); + + assertParseError(null, "DROP INDEX .idx", "Unexpected"); + + // IF EXISTS + SqlDropIndexCommand cmd; + + cmd = parseValidate(null, "DROP INDEX schema.idx", "SCHEMA", "IDX"); + assertFalse(cmd.ifExists()); + + cmd = parseValidate(null, "DROP INDEX IF EXISTS schema.idx", "SCHEMA", "IDX"); + assertTrue(cmd.ifExists()); + + assertParseError(null, "DROP INDEX IF idx", "Unexpected token: \"IDX\""); + + assertParseError(null, "DROP INDEX EXISTS idx", "Unexpected token: \"EXISTS\""); + } + + /** + * Parse and validate SQL script. + * + * @param schema Schema. + * @param sql SQL. + * @param expSchemaName Expected schema name. + * @param expIdxName Expected index name. + * @return Command. + */ + private static SqlDropIndexCommand parseValidate(String schema, String sql, String expSchemaName, + String expIdxName) { + SqlDropIndexCommand cmd = (SqlDropIndexCommand)new SqlParser(schema, sql).nextCommand(); + + validate(cmd, expSchemaName, expIdxName); + + return cmd; + } + + /** + * Validate command. + * + * @param cmd Command. + * @param expSchemaName Expected schema name. + * @param expIdxName Expected index name. + */ + private static void validate(SqlDropIndexCommand cmd, String expSchemaName, String expIdxName) { + assertEquals(expSchemaName, cmd.schemaName()); + assertEquals(expIdxName, cmd.indexName()); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/a1b6a33f/modules/core/src/test/java/org/apache/ignite/internal/sql/SqlParserSelfTest.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/apache/ignite/internal/sql/SqlParserSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/sql/SqlParserSelfTest.java deleted file mode 100644 index 98a6aae..0000000 --- a/modules/core/src/test/java/org/apache/ignite/internal/sql/SqlParserSelfTest.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.ignite.internal.sql; - -import org.apache.ignite.internal.sql.command.SqlCreateIndexCommand; -import org.apache.ignite.internal.sql.command.SqlIndexColumn; -import org.apache.ignite.internal.util.typedef.F; -import org.apache.ignite.testframework.GridTestUtils; -import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; - -import java.util.Collection; -import java.util.Iterator; -import java.util.concurrent.Callable; - -/** - * Test for parser. - */ -@SuppressWarnings({"UnusedReturnValue", "ThrowableNotThrown"}) -public class SqlParserSelfTest extends GridCommonAbstractTest { - /** - * Tests for CREATE INDEX command. - * - * @throws Exception If failed. - */ - public void testCreateIndex() throws Exception { - // Base. - parseValidate(null, "CREATE INDEX idx ON tbl(a)", null, "TBL", "IDX", "A", false); - parseValidate(null, "CREATE INDEX idx ON tbl(a ASC)", null, "TBL", "IDX", "A", false); - parseValidate(null, "CREATE INDEX idx ON tbl(a DESC)", null, "TBL", "IDX", "A", true); - - // Case (in)sensitivity. - parseValidate(null, "CREATE INDEX IDX ON TBL(COL)", null, "TBL", "IDX", "COL", false); - parseValidate(null, "CREATE INDEX iDx ON tBl(cOl)", null, "TBL", "IDX", "COL", false); - - parseValidate(null, "CREATE INDEX \"idx\" ON tbl(col)", null, "TBL", "idx", "COL", false); - parseValidate(null, "CREATE INDEX \"iDx\" ON tbl(col)", null, "TBL", "iDx", "COL", false); - - parseValidate(null, "CREATE INDEX idx ON \"tbl\"(col)", null, "tbl", "IDX", "COL", false); - parseValidate(null, "CREATE INDEX idx ON \"tBl\"(col)", null, "tBl", "IDX", "COL", false); - - parseValidate(null, "CREATE INDEX idx ON tbl(\"col\")", null, "TBL", "IDX", "col", false); - parseValidate(null, "CREATE INDEX idx ON tbl(\"cOl\")", null, "TBL", "IDX", "cOl", false); - - parseValidate(null, "CREATE INDEX idx ON tbl(\"cOl\" ASC)", null, "TBL", "IDX", "cOl", false); - parseValidate(null, "CREATE INDEX idx ON tbl(\"cOl\" DESC)", null, "TBL", "IDX", "cOl", true); - - // Columns. - parseValidate(null, "CREATE INDEX idx ON tbl(a, b)", null, "TBL", "IDX", "A", false, "B", false); - - parseValidate(null, "CREATE INDEX idx ON tbl(a ASC, b)", null, "TBL", "IDX", "A", false, "B", false); - parseValidate(null, "CREATE INDEX idx ON tbl(a, b ASC)", null, "TBL", "IDX", "A", false, "B", false); - parseValidate(null, "CREATE INDEX idx ON tbl(a ASC, b ASC)", null, "TBL", "IDX", "A", false, "B", false); - - parseValidate(null, "CREATE INDEX idx ON tbl(a DESC, b)", null, "TBL", "IDX", "A", true, "B", false); - parseValidate(null, "CREATE INDEX idx ON tbl(a, b DESC)", null, "TBL", "IDX", "A", false, "B", true); - parseValidate(null, "CREATE INDEX idx ON tbl(a DESC, b DESC)", null, "TBL", "IDX", "A", true, "B", true); - - parseValidate(null, "CREATE INDEX idx ON tbl(a ASC, b DESC)", null, "TBL", "IDX", "A", false, "B", true); - parseValidate(null, "CREATE INDEX idx ON tbl(a DESC, b ASC)", null, "TBL", "IDX", "A", true, "B", false); - - parseValidate(null, "CREATE INDEX idx ON tbl(a, b, c)", null, "TBL", "IDX", "A", false, "B", false, "C", false); - parseValidate(null, "CREATE INDEX idx ON tbl(a DESC, b, c)", null, "TBL", "IDX", "A", true, "B", false, "C", false); - parseValidate(null, "CREATE INDEX idx ON tbl(a, b DESC, c)", null, "TBL", "IDX", "A", false, "B", true, "C", false); - parseValidate(null, "CREATE INDEX idx ON tbl(a, b, c DESC)", null, "TBL", "IDX", "A", false, "B", false, "C", true); - - // Negative cases. - parseError(null, "CREATE INDEX idx ON tbl()", "Unexpected token"); - parseError(null, "CREATE INDEX idx ON tbl(a, a)", "Column already defined: A"); - parseError(null, "CREATE INDEX idx ON tbl(a, b, a)", "Column already defined: A"); - parseError(null, "CREATE INDEX idx ON tbl(b, a, a)", "Column already defined: A"); - - // Tests with schema. - parseValidate(null, "CREATE INDEX idx ON schema.tbl(a)", "SCHEMA", "TBL", "IDX", "A", false); - parseValidate(null, "CREATE INDEX idx ON \"schema\".tbl(a)", "schema", "TBL", "IDX", "A", false); - parseValidate(null, "CREATE INDEX idx ON \"sChema\".tbl(a)", "sChema", "TBL", "IDX", "A", false); - - parseValidate("SCHEMA", "CREATE INDEX idx ON tbl(a)", "SCHEMA", "TBL", "IDX", "A", false); - parseValidate("schema", "CREATE INDEX idx ON tbl(a)", "schema", "TBL", "IDX", "A", false); - parseValidate("sChema", "CREATE INDEX idx ON tbl(a)", "sChema", "TBL", "IDX", "A", false); - - // NOT EXISTS - SqlCreateIndexCommand cmd; - - cmd = parseValidate(null, "CREATE INDEX idx ON schema.tbl(a)", "SCHEMA", "TBL", "IDX", "A", false); - assertFalse(cmd.ifNotExists()); - - cmd = parseValidate(null, "CREATE INDEX IF NOT EXISTS idx ON schema.tbl(a)", "SCHEMA", "TBL", "IDX", "A", false); - assertTrue(cmd.ifNotExists()); - - parseError(null, "CREATE INDEX IF idx ON tbl(a)", "Unexpected token: \"IDX\""); - parseError(null, "CREATE INDEX IF NOT idx ON tbl(a)", "Unexpected token: \"IDX\""); - parseError(null, "CREATE INDEX IF EXISTS idx ON tbl(a)", "Unexpected token: \"EXISTS\""); - parseError(null, "CREATE INDEX NOT EXISTS idx ON tbl(a)", "Unexpected token: \"NOT\""); - - // SPATIAL - cmd = parseValidate(null, "CREATE INDEX idx ON schema.tbl(a)", "SCHEMA", "TBL", "IDX", "A", false); - assertFalse(cmd.spatial()); - - cmd = parseValidate(null, "CREATE SPATIAL INDEX idx ON schema.tbl(a)", "SCHEMA", "TBL", "IDX", "A", false); - assertTrue(cmd.spatial()); - - // UNIQUE - parseError(null, "CREATE UNIQUE INDEX idx ON tbl(a)", "Unsupported keyword: \"UNIQUE\""); - - // HASH - parseError(null, "CREATE HASH INDEX idx ON tbl(a)", "Unsupported keyword: \"HASH\""); - - // PRIMARY KEY - parseError(null, "CREATE PRIMARY KEY INDEX idx ON tbl(a)", "Unsupported keyword: \"PRIMARY\""); - } - - /** - * Make sure that parse error occurs. - * - * @param schema Schema. - * @param sql SQL. - * @param msg Expected error message. - */ - private static void parseError(final String schema, final String sql, String msg) { - GridTestUtils.assertThrows(null, new Callable() { - @Override public Void call() throws Exception { - new SqlParser(schema, sql).nextCommand(); - - return null; - } - }, SqlParseException.class, msg); - } - - /** - * Parse and validate SQL script. - * - * @param schema Schema. - * @param sql SQL. - * @param expSchemaName Expected schema name. - * @param expTblName Expected table name. - * @param expIdxName Expected index name. - * @param expColDefs Expected column definitions. - * @return Command. - */ - private static SqlCreateIndexCommand parseValidate(String schema, String sql, String expSchemaName, - String expTblName, String expIdxName, Object... expColDefs) { - SqlCreateIndexCommand cmd = (SqlCreateIndexCommand)new SqlParser(schema, sql).nextCommand(); - - validate(cmd, expSchemaName, expTblName, expIdxName, expColDefs); - - return cmd; - } - - /** - * Validate create index command. - * - * @param cmd Command. - * @param expSchemaName Expected schema name. - * @param expTblName Expected table name. - * @param expIdxName Expected index name. - * @param expColDefs Expected column definitions. - */ - private static void validate(SqlCreateIndexCommand cmd, String expSchemaName, String expTblName, String expIdxName, - Object... expColDefs) { - assertEquals(expSchemaName, cmd.schemaName()); - assertEquals(expTblName, cmd.tableName()); - assertEquals(expIdxName, cmd.indexName()); - - if (F.isEmpty(expColDefs) || expColDefs.length % 2 == 1) - throw new IllegalArgumentException("Column definitions must be even."); - - Collection cols = cmd.columns(); - - assertEquals(expColDefs.length / 2, cols.size()); - - Iterator colIter = cols.iterator(); - - for (int i = 0; i < expColDefs.length;) { - SqlIndexColumn col = colIter.next(); - - String expColName = (String)expColDefs[i++]; - Boolean expDesc = (Boolean) expColDefs[i++]; - - assertEquals(expColName, col.name()); - assertEquals(expDesc, (Boolean)col.descending()); - } - } -} http://git-wip-us.apache.org/repos/asf/ignite/blob/a1b6a33f/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java ---------------------------------------------------------------------- diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java index 884752d..52185f4 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java @@ -118,6 +118,7 @@ import org.apache.ignite.internal.processors.timeout.GridTimeoutProcessor; import org.apache.ignite.internal.sql.SqlParser; import org.apache.ignite.internal.sql.command.SqlCommand; import org.apache.ignite.internal.sql.command.SqlCreateIndexCommand; +import org.apache.ignite.internal.sql.command.SqlDropIndexCommand; import org.apache.ignite.internal.util.GridBoundedConcurrentLinkedHashMap; import org.apache.ignite.internal.util.GridEmptyCloseableIterator; import org.apache.ignite.internal.util.GridSpinBusyLock; @@ -1348,8 +1349,8 @@ public class IgniteH2Indexing implements GridQueryIndexing { if (parser.nextCommand() != null) return null; - // Only CREATE INDEX is supported for now. - if (!(cmd instanceof SqlCreateIndexCommand)) + // Only CREATE/DROP INDEX is supported for now. + if (!(cmd instanceof SqlCreateIndexCommand || cmd instanceof SqlDropIndexCommand)) return null; } catch (Exception e) { http://git-wip-us.apache.org/repos/asf/ignite/blob/a1b6a33f/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java ---------------------------------------------------------------------- diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java index fd425c2..3c8d9fe 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java @@ -53,6 +53,7 @@ import org.apache.ignite.internal.processors.query.h2.sql.GridSqlStatement; import org.apache.ignite.internal.processors.query.schema.SchemaOperationException; import org.apache.ignite.internal.sql.command.SqlCommand; import org.apache.ignite.internal.sql.command.SqlCreateIndexCommand; +import org.apache.ignite.internal.sql.command.SqlDropIndexCommand; import org.apache.ignite.internal.sql.command.SqlIndexColumn; import org.apache.ignite.internal.util.future.GridFinishedFuture; import org.apache.ignite.internal.util.typedef.F; @@ -135,9 +136,26 @@ public class DdlStatementsProcessor { newIdx.setFields(flds); - fut = ctx.query().dynamicIndexCreate(tbl.cacheName(), cmd.schemaName(), typeDesc.tableName(), + fut = ctx.query().dynamicIndexCreate(tbl.cacheName(), cmd0.schemaName(), typeDesc.tableName(), newIdx, cmd0.ifNotExists()); } + else if (cmd instanceof SqlDropIndexCommand) { + SqlDropIndexCommand cmd0 = (SqlDropIndexCommand)cmd; + + GridH2Table tbl = idx.dataTableForIndex(cmd0.schemaName(), cmd0.indexName()); + + if (tbl != null) { + fut = ctx.query().dynamicIndexDrop(tbl.cacheName(), cmd0.schemaName(), cmd0.indexName(), + cmd0.ifExists()); + } + else { + if (cmd0.ifExists()) + fut = new GridFinishedFuture(); + else + throw new SchemaOperationException(SchemaOperationException.CODE_INDEX_NOT_FOUND, + cmd0.indexName()); + } + } else throw new IgniteSQLException("Unsupported DDL operation: " + sql, IgniteQueryErrorCode.UNSUPPORTED_OPERATION); http://git-wip-us.apache.org/repos/asf/ignite/blob/a1b6a33f/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite.java ---------------------------------------------------------------------- diff --git a/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite.java b/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite.java index 5339865..16fd5e0 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite.java +++ b/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite.java @@ -154,7 +154,8 @@ import org.apache.ignite.internal.processors.query.h2.sql.GridQueryParsingTest; import org.apache.ignite.internal.processors.query.h2.sql.H2CompareBigQueryDistributedJoinsTest; import org.apache.ignite.internal.processors.query.h2.sql.H2CompareBigQueryTest; import org.apache.ignite.internal.processors.sql.SqlConnectorConfigurationValidationSelfTest; -import org.apache.ignite.internal.sql.SqlParserSelfTest; +import org.apache.ignite.internal.sql.SqlParserCreateIndexSelfTest; +import org.apache.ignite.internal.sql.SqlParserDropIndexSelfTest; import org.apache.ignite.spi.communication.tcp.GridOrderedMessageCancelSelfTest; import org.apache.ignite.testframework.IgniteTestSuite; @@ -169,7 +170,8 @@ public class IgniteCacheQuerySelfTestSuite extends TestSuite { public static TestSuite suite() throws Exception { IgniteTestSuite suite = new IgniteTestSuite("Ignite Cache Queries Test Suite"); - suite.addTestSuite(SqlParserSelfTest.class); + suite.addTestSuite(SqlParserCreateIndexSelfTest.class); + suite.addTestSuite(SqlParserDropIndexSelfTest.class); suite.addTestSuite(SqlConnectorConfigurationValidationSelfTest.class); suite.addTestSuite(ClientConnectorConfigurationValidationSelfTest.class);