44 */
55package com .microsoft .sqlserver .jdbc .unit .statement ;
66
7+ import static org .junit .jupiter .api .Assertions .assertArrayEquals ;
78import static org .junit .jupiter .api .Assertions .assertTrue ;
89import static org .junit .jupiter .api .Assertions .assertEquals ;
910import static org .junit .jupiter .api .Assertions .fail ;
1011
1112import java .lang .reflect .Field ;
13+ import java .sql .BatchUpdateException ;
14+ import java .sql .CallableStatement ;
1215import java .sql .Connection ;
1316import java .sql .PreparedStatement ;
1417import java .sql .ResultSet ;
1518import java .sql .SQLException ;
1619import java .sql .Statement ;
20+ import java .util .Arrays ;
1721
22+ import com .microsoft .sqlserver .jdbc .SQLServerPreparedStatement ;
1823import org .junit .jupiter .api .AfterAll ;
1924import org .junit .jupiter .api .BeforeAll ;
2025import org .junit .jupiter .api .Tag ;
4449@ Tag (Constants .xAzureSQLDW )
4550public class BatchExecutionTest extends AbstractTest {
4651
47- static String ctstable1 ;
48- static String ctstable2 ;
52+ private static String ctstable1 ;
53+ private static String ctstable2 ;
54+ private static String ctstable3 ;
55+ private static String ctstable4 ;
56+ private static String ctstable3Procedure1 ;
57+
58+ /**
59+ * This tests the updateCount when the error query does cause a SQL state HY008.
60+ *
61+ * @throws Exception
62+ */
63+ @ Test
64+ public void testBatchUpdateCountFalseOnFirstPstmtPrepexec () throws Exception {
65+ long [] expectedUpdateCount = {1 , 1 , 1 , 1 , -3 , -3 , -3 , -3 , -3 , -3 };
66+ testBatchUpdateCountWith (10 , 6 , false , "prepexec" , expectedUpdateCount );
67+ }
68+
69+ /**
70+ * This tests the updateCount when the error query does cause a SQL state HY008.
71+ *
72+ * @throws Exception
73+ */
74+ @ Test
75+ public void testBatchUpdateCountTrueOnFirstPstmtPrepexec () throws Exception {
76+ long [] expectedUpdateCount = {1 , 1 , -3 , -3 , -3 };
77+ testBatchUpdateCountWith (5 , 4 , true , "prepexec" , expectedUpdateCount );
78+ }
79+
80+ /**
81+ * This tests the updateCount when the error query does cause a SQL state HY008.
82+ *
83+ * @throws Exception
84+ */
85+ @ Test
86+ public void testBatchUpdateCountFalseOnFirstPstmtSpPrepare () throws Exception {
87+ long [] expectedUpdateCount = {1 , 1 , 1 , 1 , -3 , -3 , -3 , -3 , -3 , -3 };
88+ testBatchUpdateCountWith (10 , 6 , false , "prepare" , expectedUpdateCount );
89+ }
90+
91+ /**
92+ * This tests the updateCount when the error query does cause a SQL state HY008.
93+ *
94+ * @throws Exception
95+ */
96+ @ Test
97+ public void testBatchUpdateCountTrueOnFirstPstmtSpPrepare () throws Exception {
98+ long [] expectedUpdateCount = {1 , 1 , -3 , -3 , -3 };
99+ testBatchUpdateCountWith (5 , 4 , true , "prepare" , expectedUpdateCount );
100+ }
101+
102+ /**
103+ * This tests the updateCount when the error query does not cause a SQL state HY008.
104+ *
105+ * @throws Exception
106+ */
107+ @ Test
108+ public void testBatchUpdateCount () throws Exception {
109+ long [] expectedUpdateCount = {1 , 1 , 1 , 1 , -3 , 1 , 1 , 1 , 1 , 1 };
110+
111+ try (SQLServerConnection connection = PrepUtil .getConnection (connectionString )) {
112+ try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement ) connection .prepareStatement (
113+ "insert into " + AbstractSQLGenerator .escapeIdentifier (ctstable4 ) + " values(?)" )) {
114+ for (int i = 1 ; i <= 10 ; i ++) {
115+ if (i == 5 ) {
116+ pstmt .setInt (1 , -1 );
117+ } else {
118+ pstmt .setInt (1 , i );
119+ }
120+ pstmt .addBatch ();
121+ }
122+
123+ try {
124+ pstmt .executeBatch ();
125+ } catch (BatchUpdateException e ) {
126+ assertArrayEquals (expectedUpdateCount , e .getLargeUpdateCounts (),
127+ "Actual: " + Arrays .toString (e .getLargeUpdateCounts ()));
128+ }
129+ }
130+ }
131+ }
49132
50133 /**
51134 * testAddBatch1 and testExecutionBatch one looks similar except for the parameters being passed for select query.
@@ -139,6 +222,35 @@ public void testExecuteBatch1UseBulkCopyAPI() {
139222 testExecuteBatch1Internal ("BulkCopy" );
140223 }
141224
225+ private void testBatchUpdateCountWith (int numOfInserts , int errorQueryIndex ,
226+ boolean prepareOnFirstPreparedStatement , String prepareMethod ,
227+ long [] expectedUpdateCount ) throws Exception {
228+ try (SQLServerConnection connection = PrepUtil .getConnection (connectionString )) {
229+ connection .setEnablePrepareOnFirstPreparedStatementCall (prepareOnFirstPreparedStatement );
230+ connection .setPrepareMethod (prepareMethod );
231+ try (CallableStatement cstmt = connection .prepareCall (
232+ AbstractSQLGenerator .escapeIdentifier (ctstable3Procedure1 ) + " @duration=?, @value=?" )) {
233+ cstmt .setQueryTimeout (7 );
234+ for (int i = 1 ; i <= numOfInserts ; i ++) {
235+ if (i == errorQueryIndex ) {
236+ cstmt .setString (1 , "00:00:14" );
237+ } else {
238+ cstmt .setString (1 , "00:00:00" );
239+ }
240+ cstmt .setInt (2 , i );
241+ cstmt .addBatch ();
242+ }
243+
244+ try {
245+ cstmt .executeBatch ();
246+ } catch (BatchUpdateException e ) {
247+ assertArrayEquals (expectedUpdateCount , e .getLargeUpdateCounts (),
248+ "Actual: " + Arrays .toString (e .getLargeUpdateCounts ()));
249+ }
250+ }
251+ }
252+ }
253+
142254 private void testExecuteBatch1Internal (String mode ) {
143255 int i = 0 ;
144256 int retValue [] = {0 , 0 , 0 };
@@ -193,6 +305,17 @@ private void testExecuteBatch1Internal(String mode) {
193305 }
194306 }
195307
308+ private static void createProcedure () throws SQLException {
309+ String sql1 = "CREATE PROCEDURE " + AbstractSQLGenerator .escapeIdentifier (ctstable3Procedure1 ) + "\n "
310+ + "@value int,\n " + "@duration varchar(8)\n " + "AS\n " + "BEGIN\n " + "WAITFOR DELAY @duration;\n "
311+ + "INSERT INTO " + AbstractSQLGenerator .escapeIdentifier (ctstable3 ) + " VALUES (@value);\n " + "END" ;
312+
313+ try (Connection connection = PrepUtil .getConnection (connectionString );
314+ Statement stmt = (SQLServerStatement ) connection .createStatement ()) {
315+ stmt .execute (sql1 );
316+ } ;
317+ }
318+
196319 private static void createTable () throws SQLException {
197320 try (Connection connection = PrepUtil .getConnection (connectionString + ";columnEncryptionSetting=Enabled;" );
198321 Statement stmt = (SQLServerStatement ) connection .createStatement ()) {
@@ -201,8 +324,13 @@ private static void createTable() throws SQLException {
201324 String sql2 = "create table " + AbstractSQLGenerator .escapeIdentifier (ctstable2 )
202325 + " (KEY_ID int, COF_NAME varchar(32), PRICE float, TYPE_ID int, primary key(KEY_ID), foreign key(TYPE_ID) references "
203326 + AbstractSQLGenerator .escapeIdentifier (ctstable1 ) + ")" ;
327+ String sql3 = "create table " + AbstractSQLGenerator .escapeIdentifier (ctstable3 ) + "(C1 int)" ;
328+ String sql4 = "create table " + AbstractSQLGenerator .escapeIdentifier (ctstable4 )
329+ + "(C1 int check (C1 > 0))" ;
204330 stmt .execute (sql1 );
205331 stmt .execute (sql2 );
332+ stmt .execute (sql3 );
333+ stmt .execute (sql4 );
206334
207335 String sqlin2 = "insert into " + AbstractSQLGenerator .escapeIdentifier (ctstable1 )
208336 + " values (1,'COFFEE-Desc')" ;
@@ -315,15 +443,29 @@ public static void testSetup() throws TestAbortedException, Exception {
315443
316444 ctstable1 = RandomUtil .getIdentifier ("ctstable1" );
317445 ctstable2 = RandomUtil .getIdentifier ("ctstable2" );
446+ ctstable3 = RandomUtil .getIdentifier ("ctstable3" );
447+ ctstable4 = RandomUtil .getIdentifier ("ctstable4" );
448+ ctstable3Procedure1 = RandomUtil .getIdentifier ("ctstable3Procedure1" );
318449
319450 dropTable ();
320451 createTable ();
452+
453+ dropProcedure ();
454+ createProcedure ();
455+ }
456+
457+ private static void dropProcedure () throws SQLException {
458+ try (Statement stmt = connection .createStatement ()) {
459+ TestUtils .dropProcedureIfExists (AbstractSQLGenerator .escapeIdentifier (ctstable3Procedure1 ), stmt );
460+ }
321461 }
322462
323463 private static void dropTable () throws SQLException {
324464 try (Statement stmt = connection .createStatement ()) {
325465 TestUtils .dropTableIfExists (AbstractSQLGenerator .escapeIdentifier (ctstable2 ), stmt );
326466 TestUtils .dropTableIfExists (AbstractSQLGenerator .escapeIdentifier (ctstable1 ), stmt );
467+ TestUtils .dropTableIfExists (AbstractSQLGenerator .escapeIdentifier (ctstable3 ), stmt );
468+ TestUtils .dropTableIfExists (AbstractSQLGenerator .escapeIdentifier (ctstable4 ), stmt );
327469 }
328470 }
329471
0 commit comments