Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add | Implement hashCode() and equals() APIs for SQLServerDataTable and SQLServerDataColumn #1146

Merged
merged 5 commits into from
Sep 26, 2019
Merged
Show file tree
Hide file tree
Changes from 3 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 @@ -45,4 +45,35 @@ public String getColumnName() {
public int getColumnType() {
return javaSqlType;
}

@Override
public int hashCode() {
int hash = 7;
hash = 31 * hash + javaSqlType;
hash = 31 * hash + precision;
hash = 31 * hash + scale;
hash = 31 * hash + numberOfDigitsIntegerPart;
hash = 31 * hash + (null != columnName ? columnName.hashCode() : 0);
return hash;
}

@Override
public boolean equals(Object object) {
if (this == object) {
return true;
}

if (null != object && object.getClass() == SQLServerDataColumn.class) {
SQLServerDataColumn aSQLServerDataColumn = (SQLServerDataColumn) object;
if (hashCode() == aSQLServerDataColumn.hashCode()) {
// Compare objects to avoid collision
return ((null == columnName && null == aSQLServerDataColumn.columnName
ulvii marked this conversation as resolved.
Show resolved Hide resolved
|| columnName.equals(aSQLServerDataColumn.columnName))
&& javaSqlType == aSQLServerDataColumn.javaSqlType
&& numberOfDigitsIntegerPart == aSQLServerDataColumn.numberOfDigitsIntegerPart
&& precision == aSQLServerDataColumn.precision && scale == aSQLServerDataColumn.scale);
}
}
return false;
}
}
76 changes: 76 additions & 0 deletions src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataTable.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import java.text.MessageFormat;
import java.time.OffsetDateTime;
import java.time.OffsetTime;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
Expand Down Expand Up @@ -334,4 +335,79 @@ public String getTvpName() {
public void setTvpName(String tvpName) {
this.tvpName = tvpName;
}

@Override
public int hashCode() {
int hash = 7;
hash = 31 * hash + rowCount;
hash = 31 * hash + columnCount;
hash = 31 * hash + (null != columnMetadata ? columnMetadata.hashCode() : 0);
hash = 31 * hash + (null != columnNames ? columnNames.hashCode() : 0);
hash = 31 * hash + getRowsHashCode();
hash = 31 * hash + (null != tvpName ? tvpName.hashCode() : 0);
return hash;
}

@Override
public boolean equals(Object object) {
if (this == object) {
return true;
}

if (null != object && object.getClass() == SQLServerDataTable.class) {
SQLServerDataTable aSQLServerDataTable = (SQLServerDataTable) object;
if (hashCode() == aSQLServerDataTable.hashCode()) {

// Compare objects to avoid collision
boolean equalColumnMetadata = columnMetadata.equals(aSQLServerDataTable.columnMetadata);
boolean equalColumnNames = columnNames.equals(aSQLServerDataTable.columnNames);
boolean equalRowData = compareRows(aSQLServerDataTable.rows);

return (rowCount == aSQLServerDataTable.rowCount && columnCount == aSQLServerDataTable.columnCount
&& tvpName == aSQLServerDataTable.tvpName && equalColumnMetadata && equalColumnNames
&& equalRowData);
}
}
return false;
}

private int getRowsHashCode() {
if (null == rows) {
return 0;
}
int h = 0;
for (Entry<Integer, Object[]> entry : rows.entrySet()) {
h += entry.getKey() ^ Arrays.hashCode(entry.getValue());
}
return h;
}

private boolean compareRows(Map<Integer, Object[]> otherRows) {
if (rows == otherRows) {
return true;
}
if (rows.size() != otherRows.size()) {
return false;
}
try {
for (Entry<Integer, Object[]> e : rows.entrySet()) {
Integer key = e.getKey();
Object[] value = e.getValue();
if (value == null) {
ulvii marked this conversation as resolved.
Show resolved Hide resolved
if (!(otherRows.get(key) == null && otherRows.containsKey(key))) {
return false;
ulvii marked this conversation as resolved.
Show resolved Hide resolved
}
} else {
if (!Arrays.equals(value, otherRows.get(key))) {
return false;
}
}
}
} catch (ClassCastException unused) {
ulvii marked this conversation as resolved.
Show resolved Hide resolved
return false;
} catch (NullPointerException unused) {
return false;
}
return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
* Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made
* available under the terms of the MIT License. See the LICENSE file in the project root for more information.
*/

package com.microsoft.sqlserver.jdbc.tvp;
ulvii marked this conversation as resolved.
Show resolved Hide resolved

import static org.junit.Assert.assertEquals;

import java.math.BigDecimal;
import java.sql.Types;
import org.junit.jupiter.api.Test;
import org.junit.platform.runner.JUnitPlatform;
import org.junit.runner.RunWith;

import com.microsoft.sqlserver.jdbc.SQLServerDataColumn;
import com.microsoft.sqlserver.jdbc.SQLServerDataTable;
import com.microsoft.sqlserver.jdbc.SQLServerException;


@RunWith(JUnitPlatform.class)
public class SQLServerDataTableTest {

@Test
public void testClear() throws SQLServerException {
SQLServerDataTable table = new SQLServerDataTable();
SQLServerDataColumn a = new SQLServerDataColumn("foo", Types.VARCHAR);
SQLServerDataColumn b = new SQLServerDataColumn("bar", Types.INTEGER);

table.addColumnMetadata(a);
table.addColumnMetadata(b);
assertEquals(2, table.getColumnMetadata().size());

table.clear();
assertEquals(0, table.getColumnMetadata().size());

table.addColumnMetadata(a);
table.addColumnMetadata(b);
assertEquals(2, table.getColumnMetadata().size());
}

@Test
public void testHashCodes() throws SQLServerException {
// Test Null field values for SQLServerDataColumn
SQLServerDataColumn nullDataColumn1 = new SQLServerDataColumn(null, 0);
SQLServerDataColumn nullDataColumn2 = new SQLServerDataColumn(null, 0);
assert (nullDataColumn1.hashCode() == nullDataColumn2.hashCode());
assert (nullDataColumn1.equals(nullDataColumn2));

// Test Null field values for SQLServerDataTable
SQLServerDataTable nullDataTable1 = new SQLServerDataTable();
SQLServerDataTable nullDataTable2 = new SQLServerDataTable();
assert (nullDataTable1.hashCode() == nullDataTable2.hashCode());
assert (nullDataTable1.equals(nullDataTable2));

SQLServerDataColumn a = new SQLServerDataColumn("foo", Types.VARCHAR);

// Test consistent generation of hashCode
assert (a.hashCode() == a.hashCode());
assert (a.equals(a));

SQLServerDataColumn aClone = new SQLServerDataColumn("foo", Types.VARCHAR);

// Test for different instances generating same hashCode for same data
assert (a.hashCode() == aClone.hashCode());
assert (a.equals(aClone));

SQLServerDataColumn b = new SQLServerDataColumn("bar", Types.DECIMAL);
SQLServerDataTable table = createTable(a, b);

// Test consistent generation of hashCode
assert (table.hashCode() == table.hashCode());
assert (table.equals(table));

SQLServerDataTable tableClone = createTable(aClone, b);

// Test for different instances generating same hashCode for same data
assert (table.hashCode() == tableClone.hashCode());
assert (table.equals(tableClone));

// Test for non equal hashCodes
assert (a.hashCode() != b.hashCode());
assert (!a.equals(b));

SQLServerDataColumn c = new SQLServerDataColumn("bar", Types.FLOAT);
table.clear();
table = createTable(a, c);

// Test for non equal hashCodes
assert (table.hashCode() != tableClone.hashCode());
assert (!table.equals(tableClone));
}

private SQLServerDataTable createTable(SQLServerDataColumn a, SQLServerDataColumn b) throws SQLServerException {
SQLServerDataTable table = new SQLServerDataTable();
table.addColumnMetadata(a);
table.addColumnMetadata(b);
table.addRow("Hello", new BigDecimal(1.5));
table.addRow("World", new BigDecimal(5.5));
table.setTvpName("TVP_HashCode");
return table;
}
}