Skip to content

Commit

Permalink
Add | Implement hashCode() and equals() APIs for SQLServerDataTable a…
Browse files Browse the repository at this point in the history
…nd SQLServerDataColumn (#1146)

* Add | Add hashCode()/equals() methods to SQLServerDataColumn and SQLServerDataTable
  • Loading branch information
ulvii authored Sep 26, 2019
1 parent 2c5f99d commit 4a20bf9
Show file tree
Hide file tree
Showing 3 changed files with 210 additions and 0 deletions.
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
|| 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 (null == value) {
if (!(null == otherRows.get(key) && otherRows.containsKey(key))) {
return false;
}
} else {
if (!Arrays.equals(value, otherRows.get(key))) {
return false;
}
}
}
} catch (ClassCastException unused) {
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;

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;
}
}

0 comments on commit 4a20bf9

Please sign in to comment.