ignite-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From voze...@apache.org
Subject [1/2] ignite git commit: IGNITE-5620: Implemented SQLSTATE error code for server-side logic and JDBC thin client. This closes #2541.
Date Sat, 16 Sep 2017 14:41:40 GMT
Repository: ignite
Updated Branches:
  refs/heads/master 9fd82212e -> 7c4d0bc2a


http://git-wip-us.apache.org/repos/asf/ignite/blob/7c4d0bc2/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinTcpIo.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinTcpIo.java
b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinTcpIo.java
index 27b9407..70cf00e 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinTcpIo.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinTcpIo.java
@@ -22,7 +22,7 @@ import java.io.BufferedOutputStream;
 import java.io.IOException;
 import java.net.InetSocketAddress;
 import java.net.Socket;
-import java.util.List;
+import java.sql.SQLException;
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.internal.binary.BinaryReaderExImpl;
 import org.apache.ignite.internal.binary.BinaryWriterExImpl;
@@ -31,33 +31,13 @@ import org.apache.ignite.internal.binary.streams.BinaryHeapOutputStream;
 import org.apache.ignite.internal.processors.odbc.ClientListenerNioListener;
 import org.apache.ignite.internal.processors.odbc.ClientListenerProtocolVersion;
 import org.apache.ignite.internal.processors.odbc.ClientListenerRequest;
-import org.apache.ignite.internal.processors.odbc.ClientListenerResponse;
+import org.apache.ignite.internal.processors.odbc.SqlStateCode;
 import org.apache.ignite.internal.processors.odbc.jdbc.JdbcBatchExecuteRequest;
-import org.apache.ignite.internal.processors.odbc.jdbc.JdbcBatchExecuteResult;
-import org.apache.ignite.internal.processors.odbc.jdbc.JdbcMetaColumnsRequest;
-import org.apache.ignite.internal.processors.odbc.jdbc.JdbcMetaColumnsResult;
-import org.apache.ignite.internal.processors.odbc.jdbc.JdbcMetaIndexesRequest;
-import org.apache.ignite.internal.processors.odbc.jdbc.JdbcMetaIndexesResult;
-import org.apache.ignite.internal.processors.odbc.jdbc.JdbcMetaParamsRequest;
-import org.apache.ignite.internal.processors.odbc.jdbc.JdbcMetaParamsResult;
-import org.apache.ignite.internal.processors.odbc.jdbc.JdbcMetaPrimaryKeysRequest;
-import org.apache.ignite.internal.processors.odbc.jdbc.JdbcMetaPrimaryKeysResult;
-import org.apache.ignite.internal.processors.odbc.jdbc.JdbcMetaSchemasRequest;
-import org.apache.ignite.internal.processors.odbc.jdbc.JdbcMetaSchemasResult;
-import org.apache.ignite.internal.processors.odbc.jdbc.JdbcMetaTablesRequest;
-import org.apache.ignite.internal.processors.odbc.jdbc.JdbcMetaTablesResult;
-import org.apache.ignite.internal.processors.odbc.jdbc.JdbcQuery;
 import org.apache.ignite.internal.processors.odbc.jdbc.JdbcQueryCloseRequest;
-import org.apache.ignite.internal.processors.odbc.jdbc.JdbcQueryExecuteRequest;
-import org.apache.ignite.internal.processors.odbc.jdbc.JdbcQueryExecuteResult;
 import org.apache.ignite.internal.processors.odbc.jdbc.JdbcQueryFetchRequest;
-import org.apache.ignite.internal.processors.odbc.jdbc.JdbcQueryFetchResult;
 import org.apache.ignite.internal.processors.odbc.jdbc.JdbcQueryMetadataRequest;
-import org.apache.ignite.internal.processors.odbc.jdbc.JdbcQueryMetadataResult;
 import org.apache.ignite.internal.processors.odbc.jdbc.JdbcRequest;
 import org.apache.ignite.internal.processors.odbc.jdbc.JdbcResponse;
-import org.apache.ignite.internal.processors.odbc.jdbc.JdbcResult;
-import org.apache.ignite.internal.processors.odbc.jdbc.JdbcStatementType;
 import org.apache.ignite.internal.util.ipc.loopback.IpcClientTcpEndpoint;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.lang.IgniteProductVersion;
@@ -173,10 +153,10 @@ public class JdbcThinTcpIo {
     }
 
     /**
-     * @throws IgniteCheckedException On error.
+     * @throws SQLException On connection error or reject.
      * @throws IOException On IO error in handshake.
      */
-    public void start() throws IgniteCheckedException, IOException {
+    public void start() throws SQLException, IOException {
         Socket sock = new Socket();
 
         if (sockSndBuf != 0)
@@ -189,24 +169,25 @@ public class JdbcThinTcpIo {
 
         try {
             sock.connect(new InetSocketAddress(host, port));
-        }
-        catch (IOException e) {
-            throw new IgniteCheckedException("Failed to connect to server [host=" + host
+ ", port=" + port + ']', e);
-        }
 
-        endpoint = new IpcClientTcpEndpoint(sock);
+            endpoint = new IpcClientTcpEndpoint(sock);
 
-        out = new BufferedOutputStream(endpoint.outputStream());
-        in = new BufferedInputStream(endpoint.inputStream());
+            out = new BufferedOutputStream(endpoint.outputStream());
+            in = new BufferedInputStream(endpoint.inputStream());
+        }
+        catch (IOException | IgniteCheckedException e) {
+            throw new SQLException("Failed to connect to server [host=" + host + ", port="
+ port + ']',
+                SqlStateCode.CLIENT_CONNECTION_FAILED, e);
+        }
 
         handshake();
     }
 
     /**
-     * @throws IOException On error.
-     * @throws IgniteCheckedException On error.
+     * @throws IOException On IO error.
+     * @throws SQLException On connection reject.
      */
-    public void handshake() throws IOException, IgniteCheckedException {
+    public void handshake() throws IOException, SQLException {
         BinaryWriterExImpl writer = new BinaryWriterExImpl(null, new BinaryHeapOutputStream(HANDSHAKE_MSG_SIZE),
             null, null);
 
@@ -262,8 +243,9 @@ public class JdbcThinTcpIo {
             if (VER_2_1_0.equals(srvProtocolVer))
                 handshake_2_1_0();
             else {
-                throw new IgniteCheckedException("Handshake failed [driverProtocolVer=" +
CURRENT_VER +
-                    ", remoteNodeProtocolVer=" + srvProtocolVer + ", err=" + err + ']');
+                throw new SQLException("Handshake failed [driverProtocolVer=" + CURRENT_VER
+
+                    ", remoteNodeProtocolVer=" + srvProtocolVer + ", err=" + err + ']',
+                    SqlStateCode.CONNECTION_REJECTED);
             }
         }
     }
@@ -271,10 +253,10 @@ public class JdbcThinTcpIo {
     /**
      * Compatibility handshake for server version 2.1.0
      *
-     * @throws IOException On error.
-     * @throws IgniteCheckedException On error.
+     * @throws IOException On IO error.
+     * @throws SQLException On connection reject.
      */
-    public void handshake_2_1_0() throws IOException, IgniteCheckedException {
+    private void handshake_2_1_0() throws IOException, SQLException {
         BinaryWriterExImpl writer = new BinaryWriterExImpl(null, new BinaryHeapOutputStream(HANDSHAKE_MSG_SIZE),
             null, null);
 
@@ -310,38 +292,20 @@ public class JdbcThinTcpIo {
 
             ClientListenerProtocolVersion ver = ClientListenerProtocolVersion.create(maj,
min, maintenance);
 
-            throw new IgniteCheckedException("Handshake failed [driverProtocolVer=" + CURRENT_VER
+
-                ", remoteNodeProtocolVer=" + ver + ", err=" + err + ']');
+            throw new SQLException("Handshake failed [driverProtocolVer=" + CURRENT_VER +
+                ", remoteNodeProtocolVer=" + ver + ", err=" + err + ']', SqlStateCode.CONNECTION_REJECTED);
         }
     }
 
     /**
-     * @param stmtType Expected statement type.
-     * @param cache Cache name.
-     * @param fetchSize Fetch size.
-     * @param maxRows Max rows.
-     * @param sql SQL statement.
-     * @param args Query parameters.
-     * @return Execute query results.
-     * @throws IOException On error.
-     * @throws IgniteCheckedException On error.
-     */
-    public JdbcQueryExecuteResult queryExecute(JdbcStatementType stmtType, String cache,
int fetchSize, int maxRows,
-        String sql, List<Object> args)
-        throws IOException, IgniteCheckedException {
-        return sendRequest(new JdbcQueryExecuteRequest(stmtType, cache, fetchSize, maxRows,
sql,
-            args == null ? null : args.toArray(new Object[args.size()])), DYNAMIC_SIZE_MSG_CAP);
-    }
-
-    /**
      * @param req Request.
-     * @param cap Initial ouput stream capacity.
      * @return Server response.
-     * @throws IOException On IO error.
-     * @throws IgniteCheckedException On error.
+     * @throws IOException In case of IO error.
      */
     @SuppressWarnings("unchecked")
-    public <R extends JdbcResult> R sendRequest(JdbcRequest req, int cap) throws IOException,
IgniteCheckedException {
+    JdbcResponse sendRequest(JdbcRequest req) throws IOException {
+        int cap = guessCapacity(req);
+
         BinaryWriterExImpl writer = new BinaryWriterExImpl(null, new BinaryHeapOutputStream(cap),
null, null);
 
         req.writeBinary(writer);
@@ -354,125 +318,33 @@ public class JdbcThinTcpIo {
 
         res.readBinary(reader);
 
-        if (res.status() != ClientListenerResponse.STATUS_SUCCESS)
-            throw new IgniteCheckedException("Error server response: [req=" + req + ", resp="
+ res + ']');
-
-        return (R)res.response();
+        return res;
     }
 
     /**
-     * @param qryId Query ID.
-     * @param pageSize pageSize.
-     * @return Fetch results.
-     * @throws IOException On error.
-     * @throws IgniteCheckedException On error.
-     */
-    public JdbcQueryFetchResult queryFetch(Long qryId, int pageSize)
-        throws IOException, IgniteCheckedException {
-        return sendRequest(new JdbcQueryFetchRequest(qryId, pageSize), QUERY_FETCH_MSG_SIZE);
-    }
-
-
-    /**
-     * @param qryId Query ID.
-     * @return Fetch results.
-     * @throws IOException On error.
-     * @throws IgniteCheckedException On error.
-     */
-    public JdbcQueryMetadataResult queryMeta(Long qryId)
-        throws IOException, IgniteCheckedException {
-        return sendRequest(new JdbcQueryMetadataRequest(qryId), QUERY_META_MSG_SIZE);
-    }
-
-    /**
-     * @param qryId Query ID.
-     * @throws IOException On error.
-     * @throws IgniteCheckedException On error.
-     */
-    public void queryClose(long qryId) throws IOException, IgniteCheckedException {
-        sendRequest(new JdbcQueryCloseRequest(qryId), QUERY_CLOSE_MSG_SIZE);
-    }
-
-    /**
-     * @param schemaName Schema.
-     * @param batch Batch queries.
-     * @return Result.
-     * @throws IOException On error.
-     * @throws IgniteCheckedException On error.
-     */
-    public JdbcBatchExecuteResult batchExecute(String schemaName, List<JdbcQuery> batch)
-        throws IOException, IgniteCheckedException {
-        int cnt = Math.min(MAX_BATCH_QRY_CNT, batch.size());
-
-        return sendRequest(new JdbcBatchExecuteRequest(schemaName, batch), DYNAMIC_SIZE_MSG_CAP
* cnt);
-    }
-
-    /**
-     * @param schemaPtrn Schema name pattern.
-     * @param tablePtrn Table name pattern.
-     * @return Result.
-     * @throws IOException On error.
-     * @throws IgniteCheckedException On error.
-     */
-    public JdbcMetaTablesResult tablesMeta(String schemaPtrn, String tablePtrn)
-        throws IOException, IgniteCheckedException {
-        return sendRequest(new JdbcMetaTablesRequest(schemaPtrn, tablePtrn), DYNAMIC_SIZE_MSG_CAP);
-    }
-
-    /**
-     * @param schemaPtrn Schema name pattern.
-     * @param tablePtrn Table name pattern.
-     * @param columnPtrn Column name pattern.
-     * @return Result.
-     * @throws IOException On error.
-     * @throws IgniteCheckedException On error.
-     */
-    public JdbcMetaColumnsResult columnsMeta(String schemaPtrn, String tablePtrn, String
columnPtrn)
-        throws IOException, IgniteCheckedException {
-        return sendRequest(new JdbcMetaColumnsRequest(schemaPtrn, tablePtrn, columnPtrn),
DYNAMIC_SIZE_MSG_CAP);
-    }
-
-    /**
-     * @param schemaPtrn Schema name pattern.
-     * @param tablePtrn Table name pattern.
-     * @return Result.
-     * @throws IOException On error.
-     * @throws IgniteCheckedException On error.
-     */
-    public JdbcMetaIndexesResult indexMeta(String schemaPtrn, String tablePtrn) throws IOException,
IgniteCheckedException {
-        return sendRequest(new JdbcMetaIndexesRequest(schemaPtrn, tablePtrn), DYNAMIC_SIZE_MSG_CAP);
-    }
-
-    /**
-     * @param schemaPtrn Schema name pattern.
-     * @param sql SQL query.
-     * @return Result.
-     * @throws IOException On error.
-     * @throws IgniteCheckedException On error.
+     * Try to guess request capacity.
+     *
+     * @param req Request.
+     * @return Expected capacity.
      */
-    public JdbcMetaParamsResult parametersMeta(String schemaPtrn, String sql) throws IOException,
IgniteCheckedException {
-        return sendRequest(new JdbcMetaParamsRequest(schemaPtrn, sql), DYNAMIC_SIZE_MSG_CAP);
-    }
+    private static int guessCapacity(JdbcRequest req) {
+        int cap;
 
-    /**
-     * @param schemaPtrn Schema name pattern.
-     * @param tablePtrn Table name pattern.
-     * @return Result.
-     * @throws IOException On error.
-     * @throws IgniteCheckedException On error.
-     */
-    public JdbcMetaPrimaryKeysResult primaryKeysMeta(String schemaPtrn, String tablePtrn)
throws IOException, IgniteCheckedException {
-        return sendRequest(new JdbcMetaPrimaryKeysRequest(schemaPtrn, tablePtrn), DYNAMIC_SIZE_MSG_CAP);
-    }
+        if (req instanceof JdbcBatchExecuteRequest) {
+            int cnt = Math.min(MAX_BATCH_QRY_CNT, ((JdbcBatchExecuteRequest)req).queries().size());
 
-    /**
-     * @param schemaPtrn Schema name pattern.
-     * @return Result.
-     * @throws IOException On error.
-     * @throws IgniteCheckedException On error.
-     */
-    public JdbcMetaSchemasResult schemasMeta(String schemaPtrn) throws IOException, IgniteCheckedException
{
-        return sendRequest(new JdbcMetaSchemasRequest(schemaPtrn), DYNAMIC_SIZE_MSG_CAP);
+            cap = cnt * DYNAMIC_SIZE_MSG_CAP;
+        }
+        else if (req instanceof JdbcQueryCloseRequest)
+            cap = QUERY_CLOSE_MSG_SIZE;
+        else if (req instanceof JdbcQueryMetadataRequest)
+            cap = QUERY_META_MSG_SIZE;
+        else if (req instanceof JdbcQueryFetchRequest)
+            cap = QUERY_FETCH_MSG_SIZE;
+        else
+            cap = DYNAMIC_SIZE_MSG_CAP;
+
+        return cap;
     }
 
     /**
@@ -495,9 +367,8 @@ public class JdbcThinTcpIo {
     /**
      * @return Bytes of a response from server.
      * @throws IOException On error.
-     * @throws IgniteCheckedException On error.
      */
-    private byte[] read() throws IOException, IgniteCheckedException {
+    private byte[] read() throws IOException {
         byte[] sizeBytes = read(4);
 
         int msgSize  = (((0xFF & sizeBytes[3]) << 24) | ((0xFF & sizeBytes[2])
<< 16)
@@ -510,9 +381,8 @@ public class JdbcThinTcpIo {
      * @param size Count of bytes to read from stream.
      * @return Read bytes.
      * @throws IOException On error.
-     * @throws IgniteCheckedException On error.
      */
-    private byte [] read(int size) throws IOException, IgniteCheckedException {
+    private byte [] read(int size) throws IOException {
         int off = 0;
 
         byte[] data = new byte[size];
@@ -521,7 +391,7 @@ public class JdbcThinTcpIo {
             int res = in.read(data, off, size - off);
 
             if (res == -1)
-                throw new IgniteCheckedException("Failed to read incoming message (not enough
data).");
+                throw new IOException("Failed to read incoming message (not enough data).");
 
             off += res;
         }
@@ -603,7 +473,7 @@ public class JdbcThinTcpIo {
     }
 
     /**
-     * @return Ignnite server version.
+     * @return Ignite server version.
      */
     IgniteProductVersion igniteVersion() {
         return igniteVer;

http://git-wip-us.apache.org/repos/asf/ignite/blob/7c4d0bc2/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/IgniteQueryErrorCode.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/IgniteQueryErrorCode.java
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/IgniteQueryErrorCode.java
index d05c9fd..8e5af31 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/IgniteQueryErrorCode.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/IgniteQueryErrorCode.java
@@ -20,6 +20,7 @@ package org.apache.ignite.internal.processors.cache.query;
 import java.sql.SQLException;
 import javax.cache.processor.EntryProcessor;
 import org.apache.ignite.IgniteCache;
+import org.apache.ignite.internal.processors.odbc.SqlStateCode;
 
 /**
  * Error codes for query operations.
@@ -76,6 +77,9 @@ public final class IgniteQueryErrorCode {
     /** Required column already exists. */
     public final static int COLUMN_ALREADY_EXISTS = 3009;
 
+    /** Conversion failure. */
+    public final static int CONVERSION_FAILED = 3013;
+
     /* 4xxx - cache related runtime errors */
 
     /** Attempt to INSERT a key that is already in cache. */
@@ -102,13 +106,53 @@ public final class IgniteQueryErrorCode {
     }
 
     /**
-     * Create a {@link SQLException} for given code and message with null state.
+     * Create a {@link SQLException} for given code and message with detected state.
      *
      * @param msg Message.
      * @param code Ignite status code.
      * @return {@link SQLException} with given details.
      */
     public static SQLException createJdbcSqlException(String msg, int code) {
-        return new SQLException(msg, null, code);
+        return new SQLException(msg, codeToSqlState(code));
+    }
+
+    /**
+     * Map Ignite specific error code to standard SQL state.
+     * @param statusCode Ignite specific error code.
+     * @return SQL state string.
+     * @see <a href="http://en.wikibooks.org/wiki/Structured_Query_Language/SQLSTATE">Wikipedia:
SQLSTATE spec.</a>
+     * @see IgniteQueryErrorCode
+     */
+    public static String codeToSqlState(int statusCode) {
+        switch (statusCode) {
+            case DUPLICATE_KEY:
+                return SqlStateCode.CONSTRAINT_VIOLATION;
+
+            case NULL_KEY:
+            case NULL_VALUE:
+                return SqlStateCode.NULL_VALUE;
+
+            case UNSUPPORTED_OPERATION:
+                return SqlStateCode.UNSUPPORTED_OPERATION;
+
+            case CONVERSION_FAILED:
+                return SqlStateCode.CONVERSION_FAILED;
+
+            case PARSING:
+            case TABLE_NOT_FOUND:
+            case TABLE_ALREADY_EXISTS:
+            case INDEX_ALREADY_EXISTS:
+            case INDEX_NOT_FOUND:
+            case COLUMN_NOT_FOUND:
+            case COLUMN_ALREADY_EXISTS:
+            case STMT_TYPE_MISMATCH:
+            case UNEXPECTED_OPERATION:
+            case UNEXPECTED_ELEMENT_TYPE:
+            case KEY_UPDATE:
+                return SqlStateCode.PARSING_EXCEPTION;
+
+            default:
+                return SqlStateCode.INTERNAL_ERROR;
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/7c4d0bc2/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/SqlStateCode.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/SqlStateCode.java
b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/SqlStateCode.java
new file mode 100644
index 0000000..eff680f
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/SqlStateCode.java
@@ -0,0 +1,69 @@
+/*
+ * 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.processors.odbc;
+
+/**
+ * SQL state codes.
+ */
+public final class SqlStateCode {
+    /**
+     * No-op constructor to prevent instantiation.
+     */
+    private SqlStateCode() {
+        // No-op.
+    }
+
+    /** Client has failed to open connection with specified server. */
+    public final static String CLIENT_CONNECTION_FAILED = "08001";
+
+    /** Connection unexpectedly turned out to be in closed state. */
+    public final static String CONNECTION_CLOSED = "08003";
+
+    /** Connection was rejected by server. */
+    public final static String CONNECTION_REJECTED = "08004";
+
+    /** IO error during communication. */
+    public final static String CONNECTION_FAILURE = "08006";
+
+    /** Null value occurred where it wasn't expected to. */
+    public final static String NULL_VALUE = "22004";
+
+    /** Parameter type is not supported. */
+    public final static String INVALID_PARAMETER_VALUE = "22023";
+
+    /** Data integrity constraint violation. */
+    public final static String CONSTRAINT_VIOLATION = "23000";
+
+    /** Invalid result set state. */
+    public final static String INVALID_CURSOR_STATE = "24000";
+
+    /** Conversion failure. */
+    public final static String CONVERSION_FAILED = "0700B";
+
+    /** Invalid transaction level. */
+    public final static String INVALID_TRANSACTION_LEVEL = "0700E";
+
+    /** Requested operation is not supported. */
+    public final static String UNSUPPORTED_OPERATION = "0A000";
+
+    /** Parsing exception. */
+    public final static String PARSING_EXCEPTION = "42000";
+
+    /** Internal error. */
+    public final static String INTERNAL_ERROR = "50000";  // Generic value for custom "50"
class.
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/7c4d0bc2/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java
b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java
index 4250ba5..fe50bb5 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java
@@ -36,12 +36,14 @@ import org.apache.ignite.internal.IgniteVersionUtils;
 import org.apache.ignite.internal.binary.BinaryWriterExImpl;
 import org.apache.ignite.internal.jdbc2.JdbcSqlFieldsQuery;
 import org.apache.ignite.internal.processors.cache.QueryCursorImpl;
+import org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode;
 import org.apache.ignite.internal.processors.odbc.ClientListenerRequest;
 import org.apache.ignite.internal.processors.odbc.ClientListenerRequestHandler;
 import org.apache.ignite.internal.processors.odbc.ClientListenerResponse;
 import org.apache.ignite.internal.processors.odbc.odbc.OdbcQueryGetColumnsMetaRequest;
 import org.apache.ignite.internal.processors.query.GridQueryIndexDescriptor;
 import org.apache.ignite.internal.processors.query.GridQueryTypeDescriptor;
+import org.apache.ignite.internal.processors.query.IgniteSQLException;
 import org.apache.ignite.internal.processors.query.QueryUtils;
 import org.apache.ignite.internal.util.GridSpinBusyLock;
 import org.apache.ignite.internal.util.typedef.F;
@@ -138,7 +140,7 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler
{
         JdbcRequest req = (JdbcRequest)req0;
 
         if (!busyLock.enterBusy())
-            return new JdbcResponse(ClientListenerResponse.STATUS_FAILED,
+            return new JdbcResponse(IgniteQueryErrorCode.UNKNOWN,
                 "Failed to handle JDBC request because node is stopping.");
 
         try {
@@ -177,7 +179,8 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler
{
                     return getSchemas((JdbcMetaSchemasRequest)req);
             }
 
-            return new JdbcResponse(ClientListenerResponse.STATUS_FAILED, "Unsupported JDBC
request [req=" + req + ']');
+            return new JdbcResponse(IgniteQueryErrorCode.UNSUPPORTED_OPERATION,
+                "Unsupported JDBC request [req=" + req + ']');
         }
         finally {
             busyLock.leaveBusy();
@@ -186,7 +189,7 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler
{
 
     /** {@inheritDoc} */
     @Override public ClientListenerResponse handleException(Exception e) {
-        return new JdbcResponse(ClientListenerResponse.STATUS_FAILED, e.toString());
+        return exceptionToResult(e);
     }
 
     /** {@inheritDoc} */
@@ -232,7 +235,7 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler
{
         int cursorCnt = qryCursors.size();
 
         if (maxCursors > 0 && cursorCnt >= maxCursors)
-            return new JdbcResponse(ClientListenerResponse.STATUS_FAILED, "Too many opened
cursors (either close other " +
+            return new JdbcResponse(IgniteQueryErrorCode.UNKNOWN, "Too many opened cursors
(either close other " +
                 "opened cursors or increase the limit through OdbcConfiguration.setMaxOpenCursors())
" +
                 "[maximum=" + maxCursors + ", current=" + cursorCnt + ']');
 
@@ -269,8 +272,7 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler
{
             qry.setLazy(lazy);
 
             if (req.pageSize() <= 0)
-                return new JdbcResponse(ClientListenerResponse.STATUS_FAILED,
-                    "Invalid fetch size : [fetchSize=" + req.pageSize() + ']');
+                return new JdbcResponse(IgniteQueryErrorCode.UNKNOWN, "Invalid fetch size:
" + req.pageSize());
 
             qry.setPageSize(req.pageSize());
 
@@ -312,7 +314,7 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler
{
 
             U.error(log, "Failed to execute SQL query [reqId=" + req.requestId() + ", req="
+ req + ']', e);
 
-            return new JdbcResponse(ClientListenerResponse.STATUS_FAILED, e.toString());
+            return exceptionToResult(e);
         }
     }
 
@@ -327,7 +329,7 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler
{
             JdbcQueryCursor cur = qryCursors.remove(req.queryId());
 
             if (cur == null)
-                return new JdbcResponse(ClientListenerResponse.STATUS_FAILED,
+                return new JdbcResponse(IgniteQueryErrorCode.UNKNOWN,
                     "Failed to find query cursor with ID: " + req.queryId());
 
             cur.close();
@@ -339,7 +341,7 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler
{
 
             U.error(log, "Failed to close SQL query [reqId=" + req.requestId() + ", req="
+ req.queryId() + ']', e);
 
-            return new JdbcResponse(ClientListenerResponse.STATUS_FAILED, e.toString());
+            return exceptionToResult(e);
         }
     }
 
@@ -354,11 +356,11 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler
{
             JdbcQueryCursor cur = qryCursors.get(req.queryId());
 
             if (cur == null)
-                return new JdbcResponse(ClientListenerResponse.STATUS_FAILED,
+                return new JdbcResponse(IgniteQueryErrorCode.UNKNOWN,
                     "Failed to find query cursor with ID: " + req.queryId());
 
             if (req.pageSize() <= 0)
-                return new JdbcResponse(ClientListenerResponse.STATUS_FAILED,
+                return new JdbcResponse(IgniteQueryErrorCode.UNKNOWN,
                     "Invalid fetch size : [fetchSize=" + req.pageSize() + ']');
 
             cur.pageSize(req.pageSize());
@@ -376,7 +378,7 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler
{
         catch (Exception e) {
             U.error(log, "Failed to fetch SQL query result [reqId=" + req.requestId() + ",
req=" + req + ']', e);
 
-            return new JdbcResponse(ClientListenerResponse.STATUS_FAILED, e.toString());
+            return exceptionToResult(e);
         }
     }
 
@@ -389,7 +391,7 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler
{
             JdbcQueryCursor cur = qryCursors.get(req.queryId());
 
             if (cur == null)
-                return new JdbcResponse(ClientListenerResponse.STATUS_FAILED,
+                return new JdbcResponse(IgniteQueryErrorCode.UNKNOWN,
                     "Failed to find query with ID: " + req.queryId());
 
             JdbcQueryMetadataResult res = new JdbcQueryMetadataResult(req.queryId(),
@@ -400,7 +402,7 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler
{
         catch (Exception e) {
             U.error(log, "Failed to fetch SQL query result [reqId=" + req.requestId() + ",
req=" + req + ']', e);
 
-            return new JdbcResponse(ClientListenerResponse.STATUS_FAILED, e.toString());
+            return exceptionToResult(e);
         }
     }
 
@@ -451,8 +453,22 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler
{
         catch (Exception e) {
             U.error(log, "Failed to execute batch query [reqId=" + req.requestId() + ", req="
+ req + ']', e);
 
-            return new JdbcResponse(new JdbcBatchExecuteResult(Arrays.copyOf(updCnts, successQueries),
-                ClientListenerResponse.STATUS_FAILED, e.toString()));
+            int code;
+
+            String msg;
+
+            if (e instanceof IgniteSQLException) {
+                code = ((IgniteSQLException) e).statusCode();
+
+                msg = e.getMessage();
+            }
+            else {
+                code = IgniteQueryErrorCode.UNKNOWN;
+
+                msg = e.getMessage();
+            }
+
+            return new JdbcResponse(new JdbcBatchExecuteResult(Arrays.copyOf(updCnts, successQueries),
code, msg));
         }
     }
 
@@ -486,7 +502,7 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler
{
         catch (Exception e) {
             U.error(log, "Failed to get tables metadata [reqId=" + req.requestId() + ", req="
+ req + ']', e);
 
-            return new JdbcResponse(ClientListenerResponse.STATUS_FAILED, e.toString());
+            return exceptionToResult(e);
         }
     }
 
@@ -528,7 +544,7 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler
{
         catch (Exception e) {
             U.error(log, "Failed to get columns metadata [reqId=" + req.requestId() + ",
req=" + req + ']', e);
 
-            return new JdbcResponse(ClientListenerResponse.STATUS_FAILED, e.toString());
+            return exceptionToResult(e);
         }
     }
 
@@ -558,7 +574,7 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler
{
         catch (Exception e) {
             U.error(log, "Failed to get parameters metadata [reqId=" + req.requestId() +
", req=" + req + ']', e);
 
-            return new JdbcResponse(ClientListenerResponse.STATUS_FAILED, e.toString());
+            return exceptionToResult(e);
         }
     }
 
@@ -585,7 +601,7 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler
{
         catch (Exception e) {
             U.error(log, "Failed to get parameters metadata [reqId=" + req.requestId() +
", req=" + req + ']', e);
 
-            return new JdbcResponse(ClientListenerResponse.STATUS_FAILED, e.toString());
+            return exceptionToResult(e);
         }
     }
 
@@ -631,7 +647,7 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler
{
         catch (Exception e) {
             U.error(log, "Failed to get parameters metadata [reqId=" + req.requestId() +
", req=" + req + ']', e);
 
-            return new JdbcResponse(ClientListenerResponse.STATUS_FAILED, e.toString());
+            return exceptionToResult(e);
         }
     }
 
@@ -657,7 +673,7 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler
{
         catch (Exception e) {
             U.error(log, "Failed to get schemas metadata [reqId=" + req.requestId() + ",
req=" + req + ']', e);
 
-            return new JdbcResponse(ClientListenerResponse.STATUS_FAILED, e.toString());
+            return exceptionToResult(e);
         }
     }
 
@@ -672,4 +688,18 @@ public class JdbcRequestHandler implements ClientListenerRequestHandler
{
         return str != null && (F.isEmpty(ptrn) ||
             str.matches(ptrn.replace("%", ".*").replace("_", ".")));
     }
+
+    /**
+     * Create {@link JdbcResponse} bearing appropriate Ignite specific result code if possible
+     *     from given {@link Exception}.
+     *
+     * @param e Exception to convert.
+     * @return resulting {@link JdbcResponse}.
+     */
+    private JdbcResponse exceptionToResult(Exception e) {
+        if (e instanceof IgniteSQLException)
+            return new JdbcResponse(((IgniteSQLException) e).statusCode(), e.getMessage());
+        else
+            return new JdbcResponse(IgniteQueryErrorCode.UNKNOWN, e.toString());
+    }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/7c4d0bc2/modules/core/src/main/java/org/apache/ignite/internal/processors/query/IgniteSQLException.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/IgniteSQLException.java
b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/IgniteSQLException.java
index 0666493..2bacc23 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/IgniteSQLException.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/IgniteSQLException.java
@@ -22,6 +22,9 @@ import org.apache.ignite.IgniteException;
 import org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode;
 import org.jetbrains.annotations.Nullable;
 
+import static org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode.UNKNOWN;
+import static org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode.codeToSqlState;
+
 /**
  * Specific exception bearing information about query processing errors for more detailed
  * errors in JDBC driver.
@@ -38,45 +41,82 @@ public class IgniteSQLException extends IgniteException {
     /** Code to return as {@link SQLException#vendorCode} */
     private final int statusCode;
 
-    /** */
+    /**
+     * Constructor.
+     *
+     * @param msg Exception message.
+     */
     public IgniteSQLException(String msg) {
-        this(msg, null, 0);
+        this(msg, UNKNOWN, (String)null);
     }
 
     /**
-     * Minimalistic ctor accepting only {@link SQLException} as the cause.
+     * Constructor.
+     *
+     * @param cause Cause to throw this exception.
      */
     public IgniteSQLException(SQLException cause) {
         super(cause);
-        this.sqlState = null;
-        this.statusCode = 0;
+
+        this.sqlState = cause.getSQLState();
+        this.statusCode = UNKNOWN;
     }
 
-    /** */
+    /**
+     * Constructor.
+     *
+     * @param msg Exception message.
+     * @param cause Cause to throw this exception.
+     */
     public IgniteSQLException(String msg, @Nullable Throwable cause) {
-        super(msg, cause);
-        this.sqlState = null;
-        this.statusCode = 0;
+        this(msg, UNKNOWN, cause);
     }
 
-    /** */
+    /**
+     * Constructor.
+     *
+     * @param msg Exception message.
+     * @param statusCode Ignite specific error code.
+     * @param cause Cause to throw this exception.
+     * @see IgniteQueryErrorCode
+     */
     public IgniteSQLException(String msg, int statusCode, @Nullable Throwable cause) {
-        super(msg, cause);
-        this.sqlState = null;
-        this.statusCode = statusCode;
+        this(msg, statusCode, codeToSqlState(statusCode), cause);
     }
 
-    /** */
-    public IgniteSQLException(String msg, String sqlState, int statusCode) {
-        super(msg);
-        this.sqlState = sqlState;
-        this.statusCode = statusCode;
+    /**
+     * Constructor.
+     * @param msg Exception message.
+     * @param statusCode Ignite specific error code.
+     * @see IgniteQueryErrorCode
+     */
+    public IgniteSQLException(String msg, int statusCode) {
+        this(msg, statusCode, codeToSqlState(statusCode));
     }
 
-    /** */
-    public IgniteSQLException(String msg, int statusCode) {
-        super(msg);
-        this.sqlState = null;
+    /**
+     * Constructor.
+     * @param msg Exception message.
+     * @param statusCode Ignite specific error code.
+     * @param sqlState SQLSTATE standard code.
+     * @see IgniteQueryErrorCode
+     */
+    public IgniteSQLException(String msg, int statusCode, String sqlState) {
+        this(msg, statusCode, sqlState, null);
+    }
+
+    /**
+     * Constructor.
+     * @param msg Exception message.
+     * @param statusCode Ignite specific error code.
+     * @param sqlState SQLSTATE standard code.
+     * @param cause Cause to throw this exception.
+     * @see IgniteQueryErrorCode
+     */
+    private IgniteSQLException(String msg, int statusCode, String sqlState, @Nullable Throwable
cause) {
+        super(msg, cause);
+
+        this.sqlState = sqlState;
         this.statusCode = statusCode;
     }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/7c4d0bc2/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/DmlStatementsProcessor.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/DmlStatementsProcessor.java
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/DmlStatementsProcessor.java
index 0634a52..cbaa478 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/DmlStatementsProcessor.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/DmlStatementsProcessor.java
@@ -49,6 +49,7 @@ import org.apache.ignite.binary.BinaryObjectBuilder;
 import org.apache.ignite.cache.query.SqlFieldsQuery;
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.internal.GridKernalContext;
+import org.apache.ignite.internal.processors.odbc.SqlStateCode;
 import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
 import org.apache.ignite.internal.processors.cache.CacheOperationContext;
 import org.apache.ignite.internal.processors.cache.GridCacheAdapter;
@@ -663,48 +664,56 @@ public class DmlStatementsProcessor {
 
         Class<?> currCls = val.getClass();
 
-        if (val instanceof Date && currCls != Date.class && expCls == Date.class)
{
-            // H2 thinks that java.util.Date is always a Timestamp, while binary marshaller
expects
-            // precise Date instance. Let's satisfy it.
-            return new Date(((Date) val).getTime());
-        }
+        try {
+            if (val instanceof Date && currCls != Date.class && expCls ==
Date.class) {
+                // H2 thinks that java.util.Date is always a Timestamp, while binary marshaller
expects
+                // precise Date instance. Let's satisfy it.
+                return new Date(((Date) val).getTime());
+            }
 
-        // User-given UUID is always serialized by H2 to byte array, so we have to deserialize
manually
-        if (type == Value.UUID && currCls == byte[].class)
-            return U.unmarshal(desc.context().marshaller(), (byte[]) val,
-                U.resolveClassLoader(desc.context().gridConfig()));
+            // User-given UUID is always serialized by H2 to byte array, so we have to deserialize
manually
+            if (type == Value.UUID && currCls == byte[].class)
+                return U.unmarshal(desc.context().marshaller(), (byte[]) val,
+                    U.resolveClassLoader(desc.context().gridConfig()));
 
-        if (LocalDateTimeUtils.isJava8DateApiPresent()) {
-            if (val instanceof Timestamp && LocalDateTimeUtils.isLocalDateTime(expCls))
-                return LocalDateTimeUtils.valueToLocalDateTime(ValueTimestamp.get((Timestamp)val));
+            if (LocalDateTimeUtils.isJava8DateApiPresent()) {
+                if (val instanceof Timestamp && LocalDateTimeUtils.isLocalDateTime(expCls))
+                    return LocalDateTimeUtils.valueToLocalDateTime(ValueTimestamp.get((Timestamp)
val));
 
-            if (val instanceof Date && LocalDateTimeUtils.isLocalDate(expCls))
-                return LocalDateTimeUtils.valueToLocalDate(ValueDate.fromDateValue(
-                    DateTimeUtils.dateValueFromDate(((Date)val).getTime())));
+                if (val instanceof Date && LocalDateTimeUtils.isLocalDate(expCls))
+                    return LocalDateTimeUtils.valueToLocalDate(ValueDate.fromDateValue(
+                        DateTimeUtils.dateValueFromDate(((Date) val).getTime())));
 
-            if (val instanceof Time && LocalDateTimeUtils.isLocalTime(expCls))
-                return LocalDateTimeUtils.valueToLocalTime(ValueTime.get((Time)val));
-        }
+                if (val instanceof Time && LocalDateTimeUtils.isLocalTime(expCls))
+                    return LocalDateTimeUtils.valueToLocalTime(ValueTime.get((Time) val));
+            }
 
-        // We have to convert arrays of reference types manually - see https://issues.apache.org/jira/browse/IGNITE-4327
-        // Still, we only can convert from Object[] to something more precise.
-        if (type == Value.ARRAY && currCls != expCls) {
-            if (currCls != Object[].class)
-                throw new IgniteCheckedException("Unexpected array type - only conversion
from Object[] is assumed");
+            // We have to convert arrays of reference types manually -
+            // see https://issues.apache.org/jira/browse/IGNITE-4327
+            // Still, we only can convert from Object[] to something more precise.
+            if (type == Value.ARRAY && currCls != expCls) {
+                if (currCls != Object[].class)
+                    throw new IgniteCheckedException("Unexpected array type - only conversion
from Object[] " +
+                        "is assumed");
 
-            // Why would otherwise type be Value.ARRAY?
-            assert expCls.isArray();
+                // Why would otherwise type be Value.ARRAY?
+                assert expCls.isArray();
 
-            Object[] curr = (Object[]) val;
+                Object[] curr = (Object[]) val;
 
-            Object newArr = Array.newInstance(expCls.getComponentType(), curr.length);
+                Object newArr = Array.newInstance(expCls.getComponentType(), curr.length);
 
-            System.arraycopy(curr, 0, newArr, 0, curr.length);
+                System.arraycopy(curr, 0, newArr, 0, curr.length);
 
-            return newArr;
-        }
+                return newArr;
+            }
 
-        return H2Utils.convert(val, desc, type);
+            return H2Utils.convert(val, desc, type);
+        }
+        catch (Exception e) {
+            throw new IgniteSQLException("Value conversion failed [from=" + currCls.getName()
+ ", to=" +
+                expCls.getName() +']', IgniteQueryErrorCode.CONVERSION_FAILED, e);
+        }
     }
 
     /**
@@ -839,7 +848,7 @@ public class DmlStatementsProcessor {
                 String msg = "Failed to INSERT some keys because they are already in cache
" +
                     "[keys=" + sender.failedKeys() + ']';
 
-                SQLException dupEx = new SQLException(msg, null, IgniteQueryErrorCode.DUPLICATE_KEY);
+                SQLException dupEx = new SQLException(msg, SqlStateCode.CONSTRAINT_VIOLATION);
 
                 if (resEx == null)
                     resEx = dupEx;
@@ -972,7 +981,8 @@ public class DmlStatementsProcessor {
         }
 
         /** {@inheritDoc} */
-        @Override public Boolean process(MutableEntry<Object, Object> entry, Object...
arguments) throws EntryProcessorException {
+        @Override public Boolean process(MutableEntry<Object, Object> entry, Object...
arguments)
+            throws EntryProcessorException {
             if (entry.exists())
                 return false;
 
@@ -1000,7 +1010,8 @@ public class DmlStatementsProcessor {
         }
 
         /** {@inheritDoc} */
-        @Override public Boolean process(MutableEntry<Object, Object> entry, Object...
arguments) throws EntryProcessorException {
+        @Override public Boolean process(MutableEntry<Object, Object> entry, Object...
arguments)
+            throws EntryProcessorException {
             if (!entry.exists())
                 return null; // Someone got ahead of us and removed this entry, let's skip
it.
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/7c4d0bc2/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java
b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java
index a2de62b..3046c20 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java
@@ -941,7 +941,8 @@ public class GridSqlQueryParser {
         int valColsNum = cols.size() - pkCols.size();
 
         if (valColsNum == 0)
-            throw new IgniteSQLException("No cache value related columns found");
+            throw new IgniteSQLException("Table must have at least one non PRIMARY KEY column.",
+                IgniteQueryErrorCode.UNSUPPORTED_OPERATION);
 
         res.columns(cols);
         res.primaryKeyColumns(pkCols);
@@ -1014,8 +1015,36 @@ public class GridSqlQueryParser {
             case CommandInterface.ALTER_TABLE_ADD_COLUMN:
                 return parseAddColumn(stmt);
 
-            default:
-                throw new IgniteSQLException("Unsupported operation code: " + stmt.getType());
+            default: {
+                String stmtName = null;
+
+                switch (stmt.getType()) {
+                    case CommandInterface.ALTER_TABLE_ALTER_COLUMN_CHANGE_TYPE:
+                    case CommandInterface.ALTER_TABLE_ALTER_COLUMN_DEFAULT:
+                    case CommandInterface.ALTER_TABLE_ALTER_COLUMN_NOT_NULL:
+                    case CommandInterface.ALTER_TABLE_ALTER_COLUMN_RENAME:
+                    case CommandInterface.ALTER_TABLE_ALTER_COLUMN_NULL:
+                    case CommandInterface.ALTER_TABLE_ALTER_COLUMN_SELECTIVITY:
+                    case CommandInterface.ALTER_TABLE_ALTER_COLUMN_VISIBILITY:
+                        stmtName = "ALTER COLUMN";
+
+                        break;
+
+                    case CommandInterface.ALTER_TABLE_DROP_COLUMN:
+                        stmtName = "DROP COLUMN";
+
+                        break;
+                }
+
+                if (stmtName == null) {
+                    throw new IgniteSQLException("Unsupported operation: " + stmt.getSQL(),
+                        IgniteQueryErrorCode.UNSUPPORTED_OPERATION);
+                }
+                else {
+                    throw new IgniteSQLException(stmtName + " is not supported",
+                        IgniteQueryErrorCode.UNSUPPORTED_OPERATION);
+                }
+            }
         }
     }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/7c4d0bc2/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/sql/GridQueryParsingTest.java
----------------------------------------------------------------------
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/sql/GridQueryParsingTest.java
b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/sql/GridQueryParsingTest.java
index 6a78df3..61694dd 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/sql/GridQueryParsingTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/sql/GridQueryParsingTest.java
@@ -596,7 +596,7 @@ public class GridQueryParsingTest extends GridCommonAbstractTest {
             IgniteSQLException.class, "CREATE TABLE ... AS ... syntax is not supported");
 
         assertParseThrows("create table Person (id int primary key)",
-            IgniteSQLException.class, "No cache value related columns found");
+            IgniteSQLException.class, "Table must have at least one non PRIMARY KEY column.");
 
         assertParseThrows("create table Person (id int primary key, age int unique) WITH
\"template=cache\"",
             IgniteSQLException.class, "Too many constraints - only PRIMARY KEY is supported
for CREATE TABLE");


Mime
View raw message