@@ -171,4 +171,106 @@ public void testBuildLockKeyWithMultiPk() {
171171 when (executor .getTableMeta ()).thenReturn (tableMeta );
172172 assertThat (executor .buildLockKey (tableRecords )).isEqualTo (buildLockKeyExpect );
173173 }
174+
175+ @ Test
176+ public void testBuildLockKeyWithBinaryPrimaryKey () {
177+ // Test binary (byte[]) primary key handling
178+ String tableName = "test_binary_table" ;
179+ byte [] binaryPkValue1 = new byte [] {1 , 2 , 3 , 15 , -1 }; // -1 represents 0xFF in signed byte
180+ byte [] binaryPkValue2 = new byte [] {10 , 20 , 30 };
181+ String pkColumnName = "binary_id" ;
182+
183+ // Expected: test_binary_table:[1, 2, 3, 15, -1],[10, 20, 30]
184+ // Using ArrayUtils.toString() format instead of memory address like [B@1b57bff9]
185+ // Note: byte is signed in Java, so 0xFF (255) is represented as -1
186+ String expectedLockKey = tableName + ":[1, 2, 3, 15, -1],[10, 20, 30]" ;
187+
188+ // Mock fields with byte[] values
189+ Field binaryField1 = mock (Field .class );
190+ when (binaryField1 .getValue ()).thenReturn (binaryPkValue1 );
191+ Field binaryField2 = mock (Field .class );
192+ when (binaryField2 .getValue ()).thenReturn (binaryPkValue2 );
193+
194+ List <Map <String , Field >> pkRows = new ArrayList <>();
195+ pkRows .add (Collections .singletonMap (pkColumnName , binaryField1 ));
196+ pkRows .add (Collections .singletonMap (pkColumnName , binaryField2 ));
197+
198+ // Mock tableMeta
199+ TableMeta tableMeta = mock (TableMeta .class );
200+ when (tableMeta .getTableName ()).thenReturn (tableName );
201+ when (tableMeta .getPrimaryKeyOnlyName ()).thenReturn (Arrays .asList (new String [] {pkColumnName }));
202+
203+ // Mock tableRecords
204+ TableRecords tableRecords = mock (TableRecords .class );
205+ when (tableRecords .getTableMeta ()).thenReturn (tableMeta );
206+ when (tableRecords .size ()).thenReturn (pkRows .size ());
207+ when (tableRecords .pkRows ()).thenReturn (pkRows );
208+
209+ // Mock executor
210+ BaseTransactionalExecutor executor = mock (BaseTransactionalExecutor .class );
211+ when (executor .buildLockKey (tableRecords )).thenCallRealMethod ();
212+ when (executor .getTableMeta ()).thenReturn (tableMeta );
213+
214+ String actualLockKey = executor .buildLockKey (tableRecords );
215+
216+ // Verify that byte[] is properly converted to readable format
217+ assertThat (actualLockKey ).isEqualTo (expectedLockKey );
218+ // Ensure it's not using memory address format
219+ assertThat (actualLockKey ).doesNotContain ("[B@]" );
220+ assertThat (actualLockKey ).contains ("[1, 2, 3, 15, -1]" );
221+ assertThat (actualLockKey ).contains ("[10, 20, 30]" );
222+ }
223+
224+ @ Test
225+ public void testBuildLockKeyWithMixedPrimaryKeys () {
226+ // Test mixed primary keys: one regular string and one binary
227+ String tableName = "test_mixed_table" ;
228+ String stringPkValue = "user123" ;
229+ byte [] binaryPkValue = new byte [] {16 , 32 , 48 , 64 };
230+ String stringPkColumnName = "user_id" ;
231+ String binaryPkColumnName = "session_id" ;
232+
233+ // Expected: test_mixed_table:user123_[16, 32, 48, 64]
234+ String expectedLockKey = tableName + ":user123_[16, 32, 48, 64]" ;
235+
236+ // Mock fields
237+ Field stringField = mock (Field .class );
238+ when (stringField .getValue ()).thenReturn (stringPkValue );
239+ Field binaryField = mock (Field .class );
240+ when (binaryField .getValue ()).thenReturn (binaryPkValue );
241+
242+ List <Map <String , Field >> pkRows = new ArrayList <>();
243+ Map <String , Field > row = new HashMap <String , Field >() {
244+ {
245+ put (stringPkColumnName , stringField );
246+ put (binaryPkColumnName , binaryField );
247+ }
248+ };
249+ pkRows .add (row );
250+
251+ // Mock tableMeta
252+ TableMeta tableMeta = mock (TableMeta .class );
253+ when (tableMeta .getTableName ()).thenReturn (tableName );
254+ when (tableMeta .getPrimaryKeyOnlyName ())
255+ .thenReturn (Arrays .asList (new String [] {stringPkColumnName , binaryPkColumnName }));
256+
257+ // Mock tableRecords
258+ TableRecords tableRecords = mock (TableRecords .class );
259+ when (tableRecords .getTableMeta ()).thenReturn (tableMeta );
260+ when (tableRecords .size ()).thenReturn (pkRows .size ());
261+ when (tableRecords .pkRows ()).thenReturn (pkRows );
262+
263+ // Mock executor
264+ BaseTransactionalExecutor executor = mock (BaseTransactionalExecutor .class );
265+ when (executor .buildLockKey (tableRecords )).thenCallRealMethod ();
266+ when (executor .getTableMeta ()).thenReturn (tableMeta );
267+
268+ String actualLockKey = executor .buildLockKey (tableRecords );
269+
270+ // Verify mixed types are handled correctly
271+ assertThat (actualLockKey ).isEqualTo (expectedLockKey );
272+ assertThat (actualLockKey ).doesNotContain ("[B@]" );
273+ assertThat (actualLockKey ).contains ("user123" );
274+ assertThat (actualLockKey ).contains ("[16, 32, 48, 64]" );
275+ }
174276}
0 commit comments