/* * 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.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Arrays; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.platform.runner.JUnitPlatform; import org.junit.runner.RunWith; import com.microsoft.sqlserver.jdbc.SQLServerCallableStatement; import com.microsoft.sqlserver.jdbc.SQLServerDataTable; import com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement; import com.microsoft.sqlserver.testframework.AbstractTest; @RunWith(JUnitPlatform.class) public class TVPTypesTest extends AbstractTest { private static Connection conn = null; static Statement stmt = null; static ResultSet rs = null; static SQLServerDataTable tvp = null; private static String tvpName = "MaxTypesTVP"; private static String charTable = "MaxTypesTVPTable"; private static String procedureName = "procedureThatCallsTVP"; private String value = null; /** * Test a longvarchar support * * @throws SQLException */ @Test public void testLongVarchar() throws SQLException { createTables("varchar(max)"); createTVPS("varchar(max)"); StringBuffer buffer = new StringBuffer(); for (int i = 0; i < 9000; i++) buffer.append("a"); value = buffer.toString(); tvp = new SQLServerDataTable(); tvp.addColumnMetadata("c1", java.sql.Types.LONGVARCHAR); tvp.addRow(value); SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connection .prepareStatement("INSERT INTO " + charTable + " select * from ? ;"); pstmt.setStructured(1, tvpName, tvp); pstmt.execute(); rs = conn.createStatement().executeQuery("select * from " + charTable); while (rs.next()) { assertEquals(rs.getString(1), value); } if (null != pstmt) { pstmt.close(); } } /** * Test longnvarchar * * @throws SQLException */ @Test public void testLongNVarchar() throws SQLException { createTables("nvarchar(max)"); createTVPS("nvarchar(max)"); StringBuffer buffer = new StringBuffer(); for (int i = 0; i < 8001; i++) buffer.append("سس"); value = buffer.toString(); tvp = new SQLServerDataTable(); tvp.addColumnMetadata("c1", java.sql.Types.LONGNVARCHAR); tvp.addRow(value); SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connection .prepareStatement("INSERT INTO " + charTable + " select * from ? ;"); pstmt.setStructured(1, tvpName, tvp); pstmt.execute(); rs = conn.createStatement().executeQuery("select * from " + charTable); while (rs.next()) { assertEquals(rs.getString(1), value); } if (null != pstmt) { pstmt.close(); } } /** * Test xml support * * @throws SQLException */ @Test public void testXML() throws SQLException { createTables("xml"); createTVPS("xml"); value = "<vx53_e>Variable E</vx53_e>" + "<vx53_f>Variable F</vx53_f>" + "<doc>API<!-- comments --></doc>" + "<doc>The following are Japanese chars.</doc>" + "<doc> Some UTF-8 encoded characters: �������</doc>"; tvp = new SQLServerDataTable(); tvp.addColumnMetadata("c1", java.sql.Types.SQLXML); tvp.addRow(value); SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connection .prepareStatement("INSERT INTO " + charTable + " select * from ? ;"); pstmt.setStructured(1, tvpName, tvp); pstmt.execute(); Connection con = DriverManager.getConnection(connectionString); ResultSet rs = con.createStatement().executeQuery("select * from " + charTable); while (rs.next()) assertEquals(rs.getString(1), value); if (null != pstmt) { pstmt.close(); } } /** * Test ntext support * * @throws SQLException */ @Test public void testnText() throws SQLException { createTables("ntext"); createTVPS("ntext"); StringBuffer buffer = new StringBuffer(); for (int i = 0; i < 9000; i++) buffer.append("س"); value = buffer.toString(); tvp = new SQLServerDataTable(); tvp.addColumnMetadata("c1", java.sql.Types.LONGNVARCHAR); tvp.addRow(value); SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connection .prepareStatement("INSERT INTO " + charTable + " select * from ? ;"); pstmt.setStructured(1, tvpName, tvp); pstmt.execute(); Connection con = DriverManager.getConnection(connectionString); ResultSet rs = con.createStatement().executeQuery("select * from " + charTable); while (rs.next()) assertEquals(rs.getString(1), value); if (null != pstmt) { pstmt.close(); } } /** * Test text support * * @throws SQLException */ @Test public void testText() throws SQLException { createTables("text"); createTVPS("text"); StringBuffer buffer = new StringBuffer(); for (int i = 0; i < 9000; i++) buffer.append("a"); value = buffer.toString(); tvp = new SQLServerDataTable(); tvp.addColumnMetadata("c1", java.sql.Types.LONGVARCHAR); tvp.addRow(value); SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connection .prepareStatement("INSERT INTO " + charTable + " select * from ? ;"); pstmt.setStructured(1, tvpName, tvp); pstmt.execute(); Connection con = DriverManager.getConnection(connectionString); ResultSet rs = con.createStatement().executeQuery("select * from " + charTable); while (rs.next()) assertEquals(rs.getString(1), value); if (null != pstmt) { pstmt.close(); } } /** * Test text support * * @throws SQLException */ @Test public void testImage() throws SQLException { createTables("varbinary(max)"); createTVPS("varbinary(max)"); StringBuffer buffer = new StringBuffer(); for (int i = 0; i < 10000; i++) buffer.append("a"); value = buffer.toString(); tvp = new SQLServerDataTable(); tvp.addColumnMetadata("c1", java.sql.Types.LONGVARBINARY); tvp.addRow(value.getBytes()); SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connection .prepareStatement("INSERT INTO " + charTable + " select * from ? ;"); pstmt.setStructured(1, tvpName, tvp); pstmt.execute(); Connection con = DriverManager.getConnection(connectionString); ResultSet rs = con.createStatement().executeQuery("select * from " + charTable); while (rs.next()) assertTrue(parseByte(rs.getBytes(1), value.getBytes())); if (null != pstmt) { pstmt.close(); } } /** * LongVarchar with StoredProcedure * * @throws SQLException */ @Test public void testTVPLongVarchar_StoredProcedure() throws SQLException { createTables("varchar(max)"); createTVPS("varchar(max)"); createPreocedure(); StringBuffer buffer = new StringBuffer(); for (int i = 0; i < 8001; i++) buffer.append("a"); value = buffer.toString(); tvp = new SQLServerDataTable(); tvp.addColumnMetadata("c1", java.sql.Types.LONGVARCHAR); tvp.addRow(value); final String sql = "{call " + procedureName + "(?)}"; SQLServerCallableStatement P_C_statement = (SQLServerCallableStatement) connection.prepareCall(sql); P_C_statement.setStructured(1, tvpName, tvp); P_C_statement.execute(); rs = stmt.executeQuery("select * from " + charTable); while (rs.next()) assertEquals(rs.getString(1), value); if (null != P_C_statement) { P_C_statement.close(); } } /** * LongNVarchar with StoredProcedure * * @throws SQLException */ @Test public void testTVPLongNVarchar_StoredProcedure() throws SQLException { createTables("nvarchar(max)"); createTVPS("nvarchar(max)"); createPreocedure(); StringBuffer buffer = new StringBuffer(); for (int i = 0; i < 8001; i++) buffer.append("سس"); value = buffer.toString(); tvp = new SQLServerDataTable(); tvp.addColumnMetadata("c1", java.sql.Types.LONGNVARCHAR); tvp.addRow(buffer.toString()); final String sql = "{call " + procedureName + "(?)}"; SQLServerCallableStatement P_C_statement = (SQLServerCallableStatement) connection.prepareCall(sql); P_C_statement.setStructured(1, tvpName, tvp); P_C_statement.execute(); rs = stmt.executeQuery("select * from " + charTable); while (rs.next()) assertEquals(rs.getString(1), value); if (null != P_C_statement) { P_C_statement.close(); } } /** * XML with StoredProcedure * * @throws SQLException */ @Test public void testTVPXML_StoredProcedure() throws SQLException { createTables("xml"); createTVPS("xml"); createPreocedure(); value = "<vx53_e>Variable E</vx53_e>" + "<vx53_f>Variable F</vx53_f>" + "<doc>API<!-- comments --></doc>" + "<doc>The following are Japanese chars.</doc>" + "<doc> Some UTF-8 encoded characters: �������</doc>"; tvp = new SQLServerDataTable(); tvp.addColumnMetadata("c1", java.sql.Types.SQLXML); tvp.addRow(value); final String sql = "{call " + procedureName + "(?)}"; SQLServerCallableStatement P_C_statement = (SQLServerCallableStatement) connection.prepareCall(sql); P_C_statement.setStructured(1, tvpName, tvp); P_C_statement.execute(); rs = stmt.executeQuery("select * from " + charTable); while (rs.next()) assertEquals(rs.getString(1), value); if (null != P_C_statement) { P_C_statement.close(); } } /** * Text with StoredProcedure * * @throws SQLException */ @Test public void testTVPText_StoredProcedure() throws SQLException { createTables("text"); createTVPS("text"); createPreocedure(); StringBuffer buffer = new StringBuffer(); for (int i = 0; i < 9000; i++) buffer.append("a"); value = buffer.toString(); tvp = new SQLServerDataTable(); tvp.addColumnMetadata("c1", java.sql.Types.LONGVARCHAR); tvp.addRow(value); final String sql = "{call " + procedureName + "(?)}"; SQLServerCallableStatement P_C_statement = (SQLServerCallableStatement) connection.prepareCall(sql); P_C_statement.setStructured(1, tvpName, tvp); P_C_statement.execute(); rs = stmt.executeQuery("select * from " + charTable); while (rs.next()) assertEquals(rs.getString(1), value); if (null != P_C_statement) { P_C_statement.close(); } } /** * Text with StoredProcedure * * @throws SQLException */ @Test public void testTVPNText_StoredProcedure() throws SQLException { createTables("ntext"); createTVPS("ntext"); createPreocedure(); StringBuffer buffer = new StringBuffer(); for (int i = 0; i < 9000; i++) buffer.append("س"); value = buffer.toString(); tvp = new SQLServerDataTable(); tvp.addColumnMetadata("c1", java.sql.Types.LONGNVARCHAR); tvp.addRow(value); final String sql = "{call " + procedureName + "(?)}"; SQLServerCallableStatement P_C_statement = (SQLServerCallableStatement) connection.prepareCall(sql); P_C_statement.setStructured(1, tvpName, tvp); P_C_statement.execute(); rs = stmt.executeQuery("select * from " + charTable); while (rs.next()) assertEquals(rs.getString(1), value); if (null != P_C_statement) { P_C_statement.close(); } } /** * Image with StoredProcedure acts the same as varbinary(max) * * @throws SQLException */ @Test public void testTVPImage_StoredProcedure() throws SQLException { createTables("image"); createTVPS("image"); createPreocedure(); StringBuffer buffer = new StringBuffer(); for (int i = 0; i < 9000; i++) buffer.append("a"); value = buffer.toString(); tvp = new SQLServerDataTable(); tvp.addColumnMetadata("c1", java.sql.Types.LONGVARBINARY); tvp.addRow(value.getBytes()); final String sql = "{call " + procedureName + "(?)}"; SQLServerCallableStatement P_C_statement = (SQLServerCallableStatement) connection.prepareCall(sql); P_C_statement.setStructured(1, tvpName, tvp); P_C_statement.execute(); rs = stmt.executeQuery("select * from " + charTable); while (rs.next()) assertTrue(parseByte(rs.getBytes(1), value.getBytes())); if (null != P_C_statement) { P_C_statement.close(); } } @BeforeEach private void testSetup() throws SQLException { conn = DriverManager.getConnection(connectionString); stmt = conn.createStatement(); dropProcedure(); dropTables(); dropTVPS(); } @AfterAll public static void terminate() throws SQLException { conn = DriverManager.getConnection(connectionString); stmt = conn.createStatement(); dropProcedure(); dropTables(); dropTVPS(); } private static void dropProcedure() throws SQLException { String sql = " IF EXISTS (select * from sysobjects where id = object_id(N'" + procedureName + "') and OBJECTPROPERTY(id, N'IsProcedure') = 1)" + " DROP PROCEDURE " + procedureName; stmt.execute(sql); } private static void dropTables() throws SQLException { stmt.executeUpdate("if object_id('" + charTable + "','U') is not null" + " drop table " + charTable); } private static void dropTVPS() throws SQLException { stmt.executeUpdate("IF EXISTS (SELECT * FROM sys.types WHERE is_table_type = 1 AND name = '" + tvpName + "') " + " drop type " + tvpName); } private static void createPreocedure() throws SQLException { String sql = "CREATE PROCEDURE " + procedureName + " @InputData " + tvpName + " READONLY " + " AS " + " BEGIN " + " INSERT INTO " + charTable + " SELECT * FROM @InputData" + " END"; stmt.execute(sql); } private void createTables(String colType) throws SQLException { String sql = "create table " + charTable + " (c1 " + colType + " null);"; stmt.execute(sql); } private void createTVPS(String colType) throws SQLException { String TVPCreateCmd = "CREATE TYPE " + tvpName + " as table (c1 " + colType + " null)"; stmt.executeUpdate(TVPCreateCmd); } private boolean parseByte(byte[] expectedData, byte[] retrieved) { assertTrue(Arrays.equals(expectedData, Arrays.copyOf(retrieved, expectedData.length)), " unexpected BINARY value, expected"); for (int i = expectedData.length; i < retrieved.length; i++) { assertTrue(0 == retrieved[i], "unexpected data BINARY"); } return true; } @AfterEach private void terminateVariation() throws SQLException { if (null != conn) { conn.close(); } if (null != stmt) { stmt.close(); } if (null != rs) { rs.close(); } if (null != tvp) { tvp.clear(); } } }