You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by vo...@apache.org on 2017/11/09 11:38:02 UTC

ignite git commit: IGNITE-6848: SQL parser: support DROP INDEX command. This closes #3006.

Repository: ignite
Updated Branches:
  refs/heads/master 145c59dd7 -> a1b6a33ff


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/master
Commit: a1b6a33ff16b927e9c5b232a70af20f03f9b36c0
Parents: 145c59d
Author: devozerov <vo...@gridgain.com>
Authored: Thu Nov 9 14:37:54 2017 +0300
Committer: devozerov <vo...@gridgain.com>
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<Void>() {
+            @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<SqlIndexColumn> cols = cmd.columns();
+
+        assertEquals(expColDefs.length / 2, cols.size());
+
+        Iterator<SqlIndexColumn> 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<Void>() {
-            @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<SqlIndexColumn> cols = cmd.columns();
-
-        assertEquals(expColDefs.length / 2, cols.size());
-
-        Iterator<SqlIndexColumn> 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);