Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import java.sql.SQLException;
import java.util.Objects;
import org.apache.ignite.IgniteLogger;
import org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode;
import org.apache.ignite.internal.processors.query.IgniteSQLException;
import org.apache.ignite.internal.processors.query.h2.sql.GridSqlQueryParser;
import org.apache.ignite.internal.util.typedef.internal.S;
Expand Down Expand Up @@ -164,7 +163,7 @@ PreparedStatement prepareStatement(String sql, byte qryFlags) {
return stmt;
}
catch (SQLException e) {
throw new IgniteSQLException("Failed to parse query. " + e.getMessage(), IgniteQueryErrorCode.PARSING, e);
throw new IgniteSQLException("Failed to parse query. " + e.getMessage(), H2Utils.h2ErrorCode(e.getErrorCode()), e);
}
}

Expand Down Expand Up @@ -209,7 +208,7 @@ PreparedStatement prepareStatementNoCache(String sql) {
return conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
}
catch (SQLException e) {
throw new IgniteSQLException("Failed to parse query. " + e.getMessage(), IgniteQueryErrorCode.PARSING, e);
throw new IgniteSQLException("Failed to parse query. " + e.getMessage(), H2Utils.h2ErrorCode(e.getErrorCode()), e);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
import org.apache.ignite.internal.util.typedef.F;
import org.apache.ignite.internal.util.typedef.internal.SB;
import org.apache.ignite.internal.util.typedef.internal.U;
import org.h2.api.ErrorCode;
import org.h2.engine.Session;
import org.h2.index.Index;
import org.h2.jdbc.JdbcConnection;
Expand Down Expand Up @@ -1050,6 +1051,40 @@ public static <T, R> Setter<T, R> setter(Class<? extends T> cls, String fldName)
return new Setter<>(field);
}

/**
* Maps H2 error code to the matching Ignite query error code when possible.
*
* @param h2ErrCode H2 error code.
* @return Ignite query error code, or the default parsing code when there is no more specific counterpart.
*/
public static int h2ErrorCode(int h2ErrCode) {
switch (h2ErrCode) {
case ErrorCode.TABLE_OR_VIEW_ALREADY_EXISTS_1:
return IgniteQueryErrorCode.TABLE_ALREADY_EXISTS;

case ErrorCode.TABLE_OR_VIEW_NOT_FOUND_1:
return IgniteQueryErrorCode.TABLE_NOT_FOUND;

case ErrorCode.INDEX_ALREADY_EXISTS_1:
return IgniteQueryErrorCode.INDEX_ALREADY_EXISTS;

case ErrorCode.INDEX_NOT_FOUND_1:
return IgniteQueryErrorCode.INDEX_NOT_FOUND;

case ErrorCode.DUPLICATE_COLUMN_NAME_1:
return IgniteQueryErrorCode.COLUMN_ALREADY_EXISTS;

case ErrorCode.COLUMN_NOT_FOUND_1:
return IgniteQueryErrorCode.COLUMN_NOT_FOUND;

case ErrorCode.SCHEMA_NOT_FOUND_1:
return IgniteQueryErrorCode.SCHEMA_NOT_FOUND;

default:
return IgniteQueryErrorCode.PARSING;
}
}

/**
* Field getter.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -516,7 +516,8 @@ else if (!prepared.isQuery()) {
IgniteQueryErrorCode.DB_UNRECOVERABLE_ERROR, e);
}
else
throw new IgniteSQLException("Failed to parse query. " + e.getMessage(), IgniteQueryErrorCode.PARSING, e);
throw new IgniteSQLException("Failed to parse query. " + e.getMessage(),
H2Utils.h2ErrorCode(e.getErrorCode()), e);
}
catch (IgniteCheckedException e) {
throw new IgniteSQLException("Failed to parse query. " + e.getMessage(), IgniteQueryErrorCode.PARSING, e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
import java.util.concurrent.Callable;
import javax.cache.CacheException;
import org.apache.ignite.cache.query.SqlFieldsQuery;
import org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode;
import org.apache.ignite.internal.processors.query.IgniteSQLException;
import org.apache.ignite.internal.util.typedef.X;
import org.apache.ignite.testframework.GridTestUtils;
import org.junit.Test;

Expand Down Expand Up @@ -194,6 +197,53 @@ public void testDdlWrongSyntax() throws Exception {
"Failed to parse query. Syntax error in SQL statement \"ALTER TABLE TEST DROP COLUMN [*]");
}

/**
* Checks error codes of the queries failed to parse.
*
* @throws Exception If failed.
*/
@Test
public void testParseErrorCodes() throws Exception {
checkSqlErrorCode("select from wrong", IgniteQueryErrorCode.TABLE_NOT_FOUND);
checkSqlErrorCode("select wrong from test", IgniteQueryErrorCode.COLUMN_NOT_FOUND);
checkSqlErrorCode("select * from wrong_schema.test", IgniteQueryErrorCode.SCHEMA_NOT_FOUND);
checkSqlErrorCode("insert into wrong (id, val) values (3, 'val3')", IgniteQueryErrorCode.TABLE_NOT_FOUND);
checkSqlErrorCode("insert into test (id, wrong) values (3, 'val3')", IgniteQueryErrorCode.COLUMN_NOT_FOUND);
checkSqlErrorCode("insert into test (id, id) values (3, 4)", IgniteQueryErrorCode.COLUMN_ALREADY_EXISTS);
checkSqlErrorCode("alter table wrong drop column val", IgniteQueryErrorCode.TABLE_NOT_FOUND);

// Generic syntax errors must be reported with the default parsing code.
checkSqlErrorCode("select from test where", IgniteQueryErrorCode.PARSING);
}

/**
* Checks SQL error code.
*
* @param sql SQL command.
* @param expCode Expected error code.
*/
private void checkSqlErrorCode(final String sql, int expCode) {
execute("DROP TABLE IF EXISTS wrong");
execute("DROP TABLE IF EXISTS test");

execute("CREATE TABLE test (id INT PRIMARY KEY, val VARCHAR)");

execute("INSERT INTO test (id, val) VALUES (1, 'val1')");

try {
execute(sql);

fail("Exception is expected: " + sql);
}
catch (CacheException e) {
IgniteSQLException sqlEx = X.cause(e, IgniteSQLException.class);

assertNotNull("Failed to find SQL error for query: " + sql, sqlEx);

assertEquals("Unexpected error code for query: " + sql, expCode, sqlEx.statusCode());
}
}

/**
* Checks SQL error message.
*
Expand Down
37 changes: 34 additions & 3 deletions modules/platforms/cpp/odbc-test/src/errors_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
#include <string>
#include <algorithm>

#include <boost/regex.hpp>
#include <boost/test/unit_test.hpp>

#include "ignite/ignite.h"
Expand Down Expand Up @@ -192,9 +191,9 @@ BOOST_AUTO_TEST_CASE(TestSyntaxError)
{
StartAdditionalNode("Node1");

Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110;SCHEMA=PUBLIC");
Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110;SCHEMA=cache");

SQLCHAR req[] = "INSERT INTO TestType(_key, fasf) VALUES(1, 'some')";
SQLCHAR req[] = "INSERT INTO TestType(_key VALUES(1)";

SQLRETURN ret;

Expand All @@ -204,4 +203,36 @@ BOOST_AUTO_TEST_CASE(TestSyntaxError)
BOOST_CHECK_EQUAL(GetOdbcErrorState(SQL_HANDLE_STMT, stmt), "42000");
}

BOOST_AUTO_TEST_CASE(TestColumnNotFound)
{
StartAdditionalNode("Node1");

Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110;SCHEMA=cache");

SQLCHAR req[] = "INSERT INTO TestType(_key, fasf) VALUES(1, 'some')";

SQLRETURN ret;

ret = SQLExecDirect(stmt, req, SQL_NTS);

BOOST_REQUIRE_EQUAL(ret, SQL_ERROR);
BOOST_CHECK_EQUAL(GetOdbcErrorState(SQL_HANDLE_STMT, stmt), "42S22");
}

BOOST_AUTO_TEST_CASE(TestSchemaNotFound)
{
StartAdditionalNode("Node1");

Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110;SCHEMA=PUBLIC");

SQLCHAR req[] = "SELECT * FROM \"NoSuchSchema\".UNKNOWN_TABLE";

SQLRETURN ret;

ret = SQLExecDirect(stmt, req, SQL_NTS);

BOOST_REQUIRE_EQUAL(ret, SQL_ERROR);
BOOST_CHECK_EQUAL(GetOdbcErrorState(SQL_HANDLE_STMT, stmt), "3F000");
}

BOOST_AUTO_TEST_SUITE_END()
6 changes: 3 additions & 3 deletions modules/platforms/cpp/odbc-test/src/queries_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1613,15 +1613,15 @@ BOOST_AUTO_TEST_CASE(TestErrorMessage)
{
Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110;SCHEMA=cache");

// Just selecting everything to make sure everything is OK
// Provoking an error by selecting from a missing table.
SQLCHAR selectReq[] = "SELECT a FROM B";

SQLRETURN ret = SQLExecDirect(stmt, selectReq, sizeof(selectReq));
SQLRETURN ret = SQLExecDirect(stmt, selectReq, SQL_NTS);

BOOST_REQUIRE_EQUAL(ret, SQL_ERROR);

std::string error = GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt);
std::string pattern = "42000: Table \"B\" not found; SQL statement:\nSELECT a FROM B";
std::string pattern = "42S02: Table \"B\" not found; SQL statement:\nSELECT a FROM B";

if (error.substr(0, pattern.size()) != pattern)
BOOST_FAIL("'" + error + "' does not match '" + pattern + "'");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,9 @@ namespace ignite
/** Conversion failure. */
CONVERSION_FAILED = 3013,

/** Schema not found. */
SCHEMA_NOT_FOUND = 3015,

/* 4xxx - cache related runtime errors */

/** Attempt to INSERT a key that is already in cache. */
Expand Down
3 changes: 3 additions & 0 deletions modules/platforms/cpp/odbc/src/common_types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,9 @@ namespace ignite
case ResponseStatus::COLUMN_ALREADY_EXISTS:
return SqlState::S42S21_COLUMN_ALREADY_EXISTS;

case ResponseStatus::SCHEMA_NOT_FOUND:
return SqlState::S3F000_INVALID_SCHEMA_NAME;

case ResponseStatus::CACHE_NOT_FOUND:
case ResponseStatus::NULL_TABLE_DESCRIPTOR:
case ResponseStatus::CONVERSION_FAILED:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -539,7 +539,8 @@ BOOST_AUTO_TEST_CASE(TestInsertNull)
*/
BOOST_AUTO_TEST_CASE(TestSqlStateOnErrors)
{
CheckSqlStateForQuery("select * from \"UnknownCache\".UNKNOWN_TABLE", "42000");
// Unknown schema is reported as SCHEMA_NOT_FOUND, whose SQL state maps to SqlStateCode.INTERNAL_ERROR.
CheckSqlStateForQuery("select * from \"UnknownCache\".UNKNOWN_TABLE", "50000");
CheckSqlStateForQuery("select * from UNKNOWN_TABLE", "42000");
CheckSqlStateForQuery("insert into \"cacheAllFields\".TestType(_key) values(null)", "22004");
CheckSqlStateForQuery("insert into \"cacheAllFields\".TestType(_key) values('abc')", "0700B");
Expand Down
Loading