/*
* 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.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
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.SQLServerException;
import com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement;
import com.microsoft.sqlserver.jdbc.SQLServerStatement;
import com.microsoft.sqlserver.testframework.AbstractTest;
import com.microsoft.sqlserver.testframework.Utils;
@RunWith(JUnitPlatform.class)
public class TVPIssuesTest extends AbstractTest {
static Connection connection = null;
static Statement stmt = null;
private static String tvpName = "TVPIssuesTest_TVP";
private static String procedureName = "TVPIssuesTest_SP";
private static String srcTable = "TVPIssuesTest_src";
private static String desTable = "TVPIssuesTest_dest";
@Test
public void tryTVP_RS_varcharMax_4001_Issue() throws Exception {
setup();
SQLServerStatement st = (SQLServerStatement) connection.createStatement();
ResultSet rs = st.executeQuery("select * from " + srcTable);
SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connection.prepareStatement("INSERT INTO " + desTable + " select * from ? ;");
pstmt.setStructured(1, tvpName, rs);
pstmt.execute();
testDestinationTable();
}
/**
* Test exception when invalid stored procedure name is used.
*
* @throws Exception
*/
@Test
public void testExceptionWithInvalidStoredProcedureName() throws Exception {
SQLServerStatement st = (SQLServerStatement) connection.createStatement();
ResultSet rs = st.executeQuery("select * from " + srcTable);
dropProcedure();
final String sql = "{call " + procedureName + "(?)}";
SQLServerCallableStatement Cstmt = (SQLServerCallableStatement) connection.prepareCall(sql);
try {
Cstmt.setObject(1, rs);
throw new Exception("Expected Exception for invalied stored procedure name is not thrown.");
}
catch (Exception e) {
if (e instanceof SQLServerException) {
assertTrue(e.getMessage().contains("Could not find stored procedure"), "Invalid Error Message.");
}
else {
throw e;
}
}
}
private void testDestinationTable() throws SQLException, IOException {
ResultSet rs = connection.createStatement().executeQuery("select * from " + desTable);
while (rs.next()) {
assertEquals(rs.getString(1).length(), 4001, " The inserted length is truncated or not correct!");
}
if (null != rs) {
rs.close();
}
}
private static void populateSourceTable() throws SQLException {
String sql = "insert into " + srcTable + " values (?)";
StringBuffer sb = new StringBuffer();
for (int i = 0; i < 4001; i++) {
sb.append("a");
}
String value = sb.toString();
SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connection.prepareStatement(sql);
pstmt.setString(1, value);
pstmt.execute();
}
@BeforeAll
public static void beforeAll() throws SQLException {
connection = DriverManager.getConnection(connectionString);
stmt = connection.createStatement();
dropProcedure();
stmt.executeUpdate("IF EXISTS (SELECT * FROM sys.types WHERE is_table_type = 1 AND name = '" + tvpName + "') " + " drop type " + tvpName);
Utils.dropTableIfExists(srcTable, stmt);
Utils.dropTableIfExists(desTable, stmt);
String sql = "create table " + srcTable + " (c1 varchar(max) null);";
stmt.execute(sql);
sql = "create table " + desTable + " (c1 varchar(max) null);";
stmt.execute(sql);
String TVPCreateCmd = "CREATE TYPE " + tvpName + " as table (c1 varchar(max) null)";
stmt.executeUpdate(TVPCreateCmd);
createPreocedure();
populateSourceTable();
}
private static void dropProcedure() throws SQLException {
Utils.dropProcedureIfExists(procedureName, stmt);
}
private static void createPreocedure() throws SQLException {
String sql = "CREATE PROCEDURE " + procedureName + " @InputData " + tvpName + " READONLY " + " AS " + " BEGIN " + " INSERT INTO " + desTable
+ " SELECT * FROM @InputData" + " END";
stmt.execute(sql);
}
@AfterAll
public static void terminateVariation() throws SQLException {
dropProcedure();
stmt.executeUpdate("IF EXISTS (SELECT * FROM sys.types WHERE is_table_type = 1 AND name = '" + tvpName + "') " + " drop type " + tvpName);
Utils.dropTableIfExists(srcTable, stmt);
Utils.dropTableIfExists(desTable, stmt);
if (null != connection) {
connection.close();
}
if (null != stmt) {
stmt.close();
}
}
}