Skip to content

Commit

Permalink
WL#16174, Support for VECTOR data type.
Browse files Browse the repository at this point in the history
Change-Id: I76162363411033b45ac3b482f871cddef4f6a8fc
  • Loading branch information
Axyoan Marcelo committed Mar 8, 2024
1 parent 6fbbd21 commit 6758555
Show file tree
Hide file tree
Showing 11 changed files with 100 additions and 8 deletions.
2 changes: 2 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

Version 8.4.0

- WL#16174, Support for VECTOR data type.

- Fix for Bug#36380711, Tests failing due to removal of deprecated features.

- Fix for Bug#113600 (Bug#36171575), Contribution: Fix join condition for retrieval of imported primary keys.
Expand Down
12 changes: 12 additions & 0 deletions src/main/core-api/java/com/mysql/cj/MysqlType.java
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,15 @@ public enum MysqlType implements SQLType {
* Protocol: FIELD_TYPE_GEOMETRY = 255
*/
GEOMETRY("GEOMETRY", Types.BINARY, null, 0, MysqlType.IS_NOT_DECIMAL, 65535L, ""), // TODO check precision, it isn't well documented, only mentioned that WKB format is represented by BLOB
/**
* VECTOR[(M)]
* A VECTOR column with a maximum length of 65,532 (16383 x 4) bytes. An optional length M can be given for this type which indicates the maximum number of
* entries in the VECTOR, with maximum of 16383. Each entry is a 4 Byte (single-precision) floating-point value.
*
* Protocol: FIELD_TYPE_VECTOR = 242
*/
VECTOR("VECTOR", Types.LONGVARBINARY, null, 0, MysqlType.IS_NOT_DECIMAL, 65532L, "[(M)]"),

/**
* Fall-back type for those MySQL data types which c/J can't recognize.
* Handled the same as BLOB.
Expand Down Expand Up @@ -607,6 +616,8 @@ public static MysqlType getByName(String fullMysqlTypeName) {
) {
return GEOMETRY; // TODO think about different MysqlTypes for Spatial Data Types

} else if (StringUtils.indexOfIgnoreCase(typeName, "VECTOR") != -1) {
return VECTOR;
}

return UNKNOWN;
Expand Down Expand Up @@ -1009,6 +1020,7 @@ public Integer getVendorTypeNumber() {
public static final int FIELD_TYPE_YEAR = 13;
public static final int FIELD_TYPE_VARCHAR = 15;
public static final int FIELD_TYPE_BIT = 16;
public static final int FIELD_TYPE_VECTOR = 242;
public static final int FIELD_TYPE_JSON = 245;
public static final int FIELD_TYPE_NEWDECIMAL = 246;
public static final int FIELD_TYPE_ENUM = 247;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ public int findColumn(String columnName, boolean useColumnNamesInFindColumn, int
}

/**
* Check if fields with type BLOB, MEDIUMBLOB, LONGBLOB, TEXT, MEDIUMTEXT or LONGTEXT
* Check if fields with type BLOB, MEDIUMBLOB, LONGBLOB, TEXT, MEDIUMTEXT, LONGTEXT or VECTOR
* exist in this ColumnDefinition.
* This check is used for making a decision about whether we want to force a
* buffer row (better for rows with large fields).
Expand All @@ -232,6 +232,7 @@ public boolean hasLargeFields() {
case MEDIUMTEXT:
case LONGTEXT:
case JSON:
case VECTOR:
return true;
default:
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1619,6 +1619,9 @@ public static MysqlType findMysqlType(PropertySet propertySet, int mysqlTypeId,
case MysqlType.FIELD_TYPE_GEOMETRY:
return MysqlType.GEOMETRY;

case MysqlType.FIELD_TYPE_VECTOR:
return MysqlType.VECTOR;

default:
return MysqlType.UNKNOWN;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3968,6 +3968,7 @@ private byte[][] getTypeInfo(String mysqlTypeName) throws SQLException {
case DATETIME:
case TIMESTAMP:
case GEOMETRY:
case VECTOR:
case UNKNOWN:
rowVal[3] = s2b("'"); // Literal Prefix
rowVal[4] = s2b("'"); // Literal Suffix
Expand Down Expand Up @@ -4065,6 +4066,7 @@ public java.sql.ResultSet getTypeInfo() throws SQLException {
tuples.add(new ByteArrayRow(getTypeInfo("MEDIUMBLOB"), getExceptionInterceptor()));
tuples.add(new ByteArrayRow(getTypeInfo("LONGBLOB"), getExceptionInterceptor()));
tuples.add(new ByteArrayRow(getTypeInfo("BLOB"), getExceptionInterceptor()));
tuples.add(new ByteArrayRow(getTypeInfo("VECTOR"), getExceptionInterceptor()));
// java.sql.Types.VARBINARY = -3
tuples.add(new ByteArrayRow(getTypeInfo("VARBINARY"), getExceptionInterceptor()));
tuples.add(new ByteArrayRow(getTypeInfo("TINYBLOB"), getExceptionInterceptor()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1193,6 +1193,7 @@ public Object getObject(int columnIndex) throws SQLException {
case MEDIUMBLOB:
case LONGBLOB:
case BLOB:
case VECTOR:
return getBytes(columnIndex);

case YEAR:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,9 @@ public void testGetColumnsBug1099() throws Exception {
String typeName = this.rs.getString("TYPE_NAME");
//String createParams = this.rs.getString("CREATE_PARAMS");

if (typeName.equals("VECTOR") && !versionMeetsMinimum(9, 0)) {
continue;
}
if (typeName.indexOf("BINARY") == -1 && !typeName.equals("LONG VARCHAR")) {
if (!alreadyDoneTypes.containsKey(typeName)) {
alreadyDoneTypes.put(typeName, null);
Expand Down Expand Up @@ -5461,6 +5464,9 @@ public void testBug106758() throws Exception {

this.rs = dbmd.getTypeInfo();
while (this.rs.next()) {
if (this.rs.getString("TYPE_NAME").equals("VECTOR") && !versionMeetsMinimum(9, 0)) {
continue;
}
StringBuilder sb = new StringBuilder("CREATE TEMPORARY TABLE testBug106758 (col ");
sb.append(this.rs.getString("TYPE_NAME"));
if (this.rs.getString("CREATE_PARAMS").startsWith("(M)")) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1977,6 +1977,9 @@ public void testAllTypesForNull() throws Exception {
StringBuilder insertValues = new StringBuilder();

while (this.rs.next()) {
if (this.rs.getString("TYPE_NAME").equals("VECTOR") && !versionMeetsMinimum(9, 0)) {
continue;
}
String dataType = this.rs.getString("TYPE_NAME").toUpperCase();

boolean wasDateTime = false;
Expand All @@ -2003,6 +2006,8 @@ public void testAllTypesForNull() throws Exception {
} else if (dataType.indexOf("DATE") != -1 || dataType.indexOf("TIME") != -1) {
insertValues.append("NOW()");
wasDateTime = true;
} else if (dataType.indexOf("VECTOR") != -1) {
insertValues.append("0x00000000");
} else {
insertValues.append("0");
}
Expand Down
37 changes: 37 additions & 0 deletions src/test/java/testsuite/simple/MetadataTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@

import org.junit.jupiter.api.Test;

import com.mysql.cj.MysqlType;
import com.mysql.cj.Query;
import com.mysql.cj.ServerVersion;
import com.mysql.cj.conf.PropertyDefinitions;
Expand Down Expand Up @@ -1887,4 +1888,40 @@ private void testGetBestRowIdentifier_checkResult(ResultSet rs1) throws Exceptio
assertFalse(rs1.next());
}

/**
* WL#16174: Support for VECTOR data type
*
* This test checks that the type of the VECTOR column is reported back as MysqlType.VECTOR. VECTOR support was added in MySQL 9.0.0.
*
* @throws Exception
*/
@Test
public void testVectorColumnType() throws Exception {
assumeTrue(versionMeetsMinimum(9, 0), "MySQL 9.0.0+ is needed to run this test.");
createTable("testVectorColumnType", "(v VECTOR)");
DatabaseMetaData md = this.conn.getMetaData();
this.rs = md.getColumns(null, null, "testVectorColumnType", "v");
this.rs.next();
assertEquals(MysqlType.VECTOR.getName().toUpperCase(), this.rs.getString("TYPE_NAME").toUpperCase());
}

/**
* WL#16174: Support for VECTOR data type
*
* This test checks that the result set metadata reports back the VECTOR column as MysqlType.VECTOR. VECTOR support was added in MySQL 9.0.0.
*
* @throws Exception
*/
@Test
public void testVectorResultSetType() throws Exception {
assumeTrue(versionMeetsMinimum(9, 0), "MySQL 9.0.0+ is needed to run this test.");
createTable("testVectorResultSetType", "(v VECTOR)");
// 0xC3F5484014AE0F41 is the HEX representation for the vector [3.14000e+00,8.98000e+00]
this.stmt.execute("INSERT INTO testVectorResultSetType VALUES(0xC3F5484014AE0F41)");
this.rs = this.stmt.executeQuery("SELECT v FROM testVectorResultSetType");
this.rs.next();
ResultSetMetaData md = this.rs.getMetaData();
assertEquals(MysqlType.VECTOR.getName().toUpperCase(), md.getColumnTypeName(1).toUpperCase());
}

}
26 changes: 26 additions & 0 deletions src/test/java/testsuite/simple/ResultSetTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assumptions.assumeTrue;

import java.io.InputStream;
import java.io.Reader;
Expand Down Expand Up @@ -61,6 +62,7 @@
import com.mysql.cj.exceptions.MysqlErrorNumbers;
import com.mysql.cj.jdbc.ConnectionImpl;
import com.mysql.cj.jdbc.exceptions.NotUpdatable;
import com.mysql.cj.util.StringUtils;

import testsuite.BaseTestCase;

Expand Down Expand Up @@ -1139,4 +1141,28 @@ public void testUpdateForReadOnlyResultSet() throws SQLException {
});
}

/**
* WL#16174: Support for VECTOR data type
*
* This test checks that the value of the VECTOR column is retrieved as a byte array by ResultSet.getObject() and that it can also be retrieved as BLOB by
* ResultSet.getBlob(). VECTOR support was added in MySQL 9.0.0.
*
* @throws Exception
*/
@Test
public void testVectorResultSet() throws Exception {
assumeTrue(versionMeetsMinimum(9, 0), "MySQL 9.0.0+ is needed to run this test.");
createTable("testVectorResultSet", "(v VECTOR)");
// 0xC3F5484014AE0F41 is the HEX representation for the vector [3.14000e+00,8.98000e+00]
String vectorHexString = "C3F5484014AE0F41";
this.stmt.execute("INSERT INTO testVectorResultSet VALUES(0x" + vectorHexString + ")");
this.rs = this.stmt.executeQuery("SELECT v FROM testVectorResultSet");
this.rs.next();
byte[] vectorObject = this.rs.getObject(1, byte[].class);
Blob vectorBlob = this.rs.getBlob(1);
byte[] vectorBlobToBytes = vectorBlob.getBytes(1, (int) vectorBlob.length());
assertEquals(vectorHexString.toUpperCase(), StringUtils.toHexString(vectorObject, vectorObject.length).toUpperCase());
assertEquals(vectorHexString.toUpperCase(), StringUtils.toHexString(vectorBlobToBytes, vectorBlobToBytes.length).toUpperCase());
}

}
11 changes: 4 additions & 7 deletions src/test/java/testsuite/simple/StatementsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -1472,7 +1472,7 @@ public void testBatchRewriteErrors() throws Exception {
props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.useServerPrepStmts.getKeyName(), "false");
props.setProperty(PropertyKey.maxAllowedPacket.getKeyName(), "5690");
props.setProperty(PropertyKey.maxAllowedPacket.getKeyName(), "5725");
props.setProperty(PropertyKey.rewriteBatchedStatements.getKeyName(), "true");
Connection multiConn = null;

Expand All @@ -1498,8 +1498,7 @@ public void testBatchRewriteErrors() throws Exception {
this.pstmt.executeBatch();
} catch (BatchUpdateException bUpE) {
int[] counts = bUpE.getUpdateCounts();

for (int i = 3530; i < counts.length; i++) {
for (int i = 3555; i < counts.length; i++) {
assertEquals(Statement.EXECUTE_FAILED, counts[i]);
}

Expand All @@ -1513,8 +1512,7 @@ public void testBatchRewriteErrors() throws Exception {
multiStmt.executeBatch();
} catch (BatchUpdateException bUpE) {
int[] counts = bUpE.getUpdateCounts();

for (int i = 4091; i < counts.length; i++) {
for (int i = 4095; i < counts.length; i++) {
assertEquals(Statement.EXECUTE_FAILED, counts[i]);
}

Expand All @@ -1540,8 +1538,7 @@ public void testBatchRewriteErrors() throws Exception {
cStmt.executeBatch();
} catch (BatchUpdateException bUpE) {
int[] counts = bUpE.getUpdateCounts();

for (int i = 3950; i < counts.length; i++) {
for (int i = 3991; i < counts.length; i++) {
assertEquals(Statement.EXECUTE_FAILED, counts[i]);
}

Expand Down

0 comments on commit 6758555

Please sign in to comment.