Skip to content
Permalink
Browse files
IGNITE-16411 Fix NPE on JdbcDatabaseMetadata.getColumns - Fixes #604.
Signed-off-by: zstan <stanilovsky@gmail.com>
  • Loading branch information
vladErmakov07 authored and zstan committed Jan 31, 2022
1 parent 59eed92 commit 4bca20b080d812093a41a15b774b8a469d91e340
Showing 6 changed files with 161 additions and 61 deletions.
@@ -23,6 +23,7 @@
import org.apache.ignite.internal.client.proto.ClientMessagePacker;
import org.apache.ignite.internal.client.proto.ClientMessageUnpacker;
import org.apache.ignite.internal.tostring.S;
import org.apache.ignite.internal.util.CollectionUtils;

/**
* JDBC batch execute request.
@@ -51,8 +52,7 @@ public BatchExecuteRequest() {
* @param autoCommit Client auto commit flag state.
*/
public BatchExecuteRequest(String schemaName, List<Query> queries, boolean autoCommit) {

assert queries != null || !queries.isEmpty();
assert !CollectionUtils.nullOrEmpty(queries);

this.schemaName = schemaName;
this.queries = queries;
@@ -89,7 +89,7 @@ boolean autoCommit() {
/** {@inheritDoc} */
@Override
public void writeBinary(ClientMessagePacker packer) {
packer.packString(schemaName);
ClientMessageUtils.writeStringNullable(packer, schemaName);

packer.packArrayHeader(queries.size());

@@ -101,7 +101,7 @@ public void writeBinary(ClientMessagePacker packer) {
/** {@inheritDoc} */
@Override
public void readBinary(ClientMessageUnpacker unpacker) {
schemaName = unpacker.unpackString();
schemaName = ClientMessageUtils.readStringNullable(unpacker);

int n = unpacker.unpackArrayHeader();

@@ -84,17 +84,17 @@ public String columnName() {
/** {@inheritDoc} */
@Override
public void writeBinary(ClientMessagePacker packer) {
packer.packString(schemaName);
packer.packString(tblName);
packer.packString(colName);
ClientMessageUtils.writeStringNullable(packer, schemaName);
ClientMessageUtils.writeStringNullable(packer, tblName);
ClientMessageUtils.writeStringNullable(packer, colName);
}

/** {@inheritDoc} */
@Override
public void readBinary(ClientMessageUnpacker unpacker) {
schemaName = unpacker.unpackString();
tblName = unpacker.unpackString();
colName = unpacker.unpackString();
schemaName = ClientMessageUtils.readStringNullable(unpacker);
tblName = ClientMessageUtils.readStringNullable(unpacker);
colName = ClientMessageUtils.readStringNullable(unpacker);
}

/** {@inheritDoc} */
@@ -71,15 +71,23 @@ public Object[] args() {
/** {@inheritDoc} */
@Override
public void writeBinary(ClientMessagePacker packer) {
packer.packString(sql);
packer.packObjectArray(args);
ClientMessageUtils.writeStringNullable(packer, sql);
if (args == null) {
packer.packNil();
} else {
packer.packObjectArray(args);
}
}

/** {@inheritDoc} */
@Override
public void readBinary(ClientMessageUnpacker unpacker) {
sql = unpacker.unpackString();
args = unpacker.unpackObjectArray();
sql = ClientMessageUtils.readStringNullable(unpacker);
if (unpacker.tryUnpackNil()) {
args = null;
} else {
args = unpacker.unpackObjectArray();
}
}

/** {@inheritDoc} */
@@ -280,9 +280,8 @@ public void setAutoCommit(boolean autoCommit) throws SQLException {

if (autoCommit != this.autoCommit) {
this.autoCommit = autoCommit;

doCommit(); // Specification requires to commit current tx if 'autoCommit' state was changed.
}
//TODO: to be implemented https://issues.apache.org/jira/browse/IGNITE-16432
}

/** {@inheritDoc} */
@@ -301,8 +300,7 @@ public void commit() throws SQLException {
if (autoCommit) {
throw new SQLException("Transaction cannot be committed explicitly in auto-commit mode.");
}

doCommit();
//TODO: to be implemented https://issues.apache.org/jira/browse/IGNITE-16432
}

/** {@inheritDoc} */
@@ -313,10 +311,7 @@ public void rollback() throws SQLException {
if (autoCommit) {
throw new SQLException("Transaction cannot be rolled back explicitly in auto-commit mode.");
}

try (Statement s = createStatement()) {
s.execute("ROLLBACK");
}
//TODO: to be implemented https://issues.apache.org/jira/browse/IGNITE-16432
}

/** {@inheritDoc} */
@@ -786,17 +781,6 @@ public boolean isWrapperFor(Class<?> iface) throws SQLException {
return iface != null && iface.isAssignableFrom(JdbcConnection.class);
}

/**
* Send to the server {@code COMMIT} command.
*
* @throws SQLException if failed.
*/
private void doCommit() throws SQLException {
try (Statement s = createStatement()) {
s.execute("COMMIT");
}
}

/**
* Remove statement from statements set.
*
@@ -204,13 +204,34 @@ public void testGetColumns() throws Exception {

ResultSet rs = meta.getColumns("IGNITE", "PUBLIC", "PERSON", "%");

checkPersonTableColumns(rs);

rs = meta.getColumns(null, "PUBLIC", "PERSON", null);

checkPersonTableColumns(rs);

rs = meta.getColumns("IGNITE", "PUBLIC", "ORGANIZATION", "%");

checkOrgTableColumns(rs);

rs = meta.getColumns(null, "PUBLIC", "ORGANIZATION", null);

checkOrgTableColumns(rs);
}

/**
* Checks organisation table column names and types.
*
* @param rs ResultSet.
* */
private void checkOrgTableColumns(ResultSet rs) throws SQLException {
assertNotNull(rs);

Collection<String> names = new ArrayList<>(2);
Collection<String> names = new ArrayList<>();

names.add("ID");
names.add("NAME");
names.add("AGE");
names.add("ORGID");
names.add("BIGDATA");

int cnt = 0;

@@ -219,57 +240,64 @@ public void testGetColumns() throws Exception {

assertTrue(names.remove(name));

if ("NAME".equals(name)) {
if ("ID".equals(name)) {
assertEquals(INTEGER, rs.getInt("DATA_TYPE"));
assertEquals(rs.getString("TYPE_NAME"), "INTEGER");
assertEquals(0, rs.getInt("NULLABLE"));
} else if ("NAME".equals(name)) {
assertEquals(VARCHAR, rs.getInt("DATA_TYPE"));
assertEquals(rs.getString("TYPE_NAME"), "VARCHAR");
assertEquals(1, rs.getInt("NULLABLE"));
} else if ("AGE".equals(name)) {
assertEquals(INTEGER, rs.getInt("DATA_TYPE"));
assertEquals(rs.getString("TYPE_NAME"), "INTEGER");
} else if ("BIGDATA".equals(name)) {
assertEquals(DECIMAL, rs.getInt("DATA_TYPE"));
assertEquals(rs.getString("TYPE_NAME"), "DECIMAL");
assertEquals(1, rs.getInt("NULLABLE"));
} else if ("ORGID".equals(name)) {
assertEquals(INTEGER, rs.getInt("DATA_TYPE"));
assertEquals(rs.getString("TYPE_NAME"), "INTEGER");
assertEquals(0, rs.getInt("NULLABLE"));

assertEquals(10, rs.getInt("DECIMAL_DIGITS"));
assertEquals(20, rs.getInt("COLUMN_SIZE"));
}

cnt++;
}

assertTrue(names.isEmpty());
assertEquals(3, cnt);
}

rs = meta.getColumns("IGNITE", "PUBLIC", "ORGANIZATION", "%");

/**
* Checks person table column names and types.
*
* @param rs ResultSet.
* */
private void checkPersonTableColumns(ResultSet rs) throws SQLException {
assertNotNull(rs);

names.add("ID");
Collection<String> names = new ArrayList<>(3);

names.add("NAME");
names.add("BIGDATA");
names.add("AGE");
names.add("ORGID");

cnt = 0;
int cnt = 0;

while (rs.next()) {
String name = rs.getString("COLUMN_NAME");

assertTrue(names.remove(name));

if ("ID".equals(name)) {
assertEquals(INTEGER, rs.getInt("DATA_TYPE"));
assertEquals(rs.getString("TYPE_NAME"), "INTEGER");
assertEquals(0, rs.getInt("NULLABLE"));
} else if ("NAME".equals(name)) {
if ("NAME".equals(name)) {
assertEquals(VARCHAR, rs.getInt("DATA_TYPE"));
assertEquals(rs.getString("TYPE_NAME"), "VARCHAR");
assertEquals(1, rs.getInt("NULLABLE"));
} else if ("BIGDATA".equals(name)) {
assertEquals(DECIMAL, rs.getInt("DATA_TYPE"));
assertEquals(rs.getString("TYPE_NAME"), "DECIMAL");
} else if ("AGE".equals(name)) {
assertEquals(INTEGER, rs.getInt("DATA_TYPE"));
assertEquals(rs.getString("TYPE_NAME"), "INTEGER");
assertEquals(1, rs.getInt("NULLABLE"));
assertEquals(10, rs.getInt("DECIMAL_DIGITS"));
assertEquals(20, rs.getInt("COLUMN_SIZE"));
}
} else if ("ORGID".equals(name)) {
assertEquals(INTEGER, rs.getInt("DATA_TYPE"));
assertEquals(rs.getString("TYPE_NAME"), "INTEGER");
assertEquals(0, rs.getInt("NULLABLE"));

}
cnt++;
}

@@ -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.runner.app.jdbc;

import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.sql.BatchUpdateException;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import org.junit.jupiter.api.Test;

/**
* Statement batch test. Now it only checks if the data is sent
* to the server correctly and if the error is correct.
*/
public class ItJdbcStatementBatchingSelfTest extends AbstractJdbcSelfTest {

/** {@inheritDoc} */
@Override protected void beforeTest() throws Exception {
super.beforeTest();
}

/**
* Test metadata batch support flag.
*
* @throws SQLException If failed.
*/
@Test
public void testDatabaseMetadataBatchSupportFlag() throws SQLException {
DatabaseMetaData meta = conn.getMetaData();

assertNotNull(meta);

assertTrue(meta.supportsBatchUpdates());
}

/**
* Test batch execution.
*
* @throws SQLException If failed.
*/
@Test
public void testBatch() throws SQLException {
try (Statement stmt = conn.createStatement()) {
stmt.addBatch("INSERT INTO Person(_key, id, firstName, lastName, age, data) "
+ "VALUES ('p1', 0, 'J', 'W', 250, RAWTOHEX('W'))");

stmt.addBatch("INSERT INTO Person(_key, id, firstName, lastName, age, data) VALUES "
+ "('p1', 1, 'John', 'White', 25, RAWTOHEX('White')), "
+ "('p2', 2, 'Joe', 'Black', 35, RAWTOHEX('Black')), "
+ "('p3', 0, 'M', 'G', 4, RAWTOHEX('G'))");

stmt.addBatch("UPDATE Person SET id = 3, firstName = 'Mike', lastName = 'Green', "
+ "age = 40, data = RAWTOHEX('Green') WHERE _key = 'p3'");

stmt.addBatch("DELETE FROM Person WHERE _key = 'p1'");

assertThrows(BatchUpdateException.class, stmt::executeBatch,
"ExecuteBatch operation is not implemented yet.");
}
}
}

0 comments on commit 4bca20b

Please sign in to comment.