From c9f41dc9b7de2aed1633c28b22597181a5cdd38b Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Thu, 1 Aug 2019 12:23:05 +0100 Subject: [PATCH] HHH-13512 Avoid allocating an array in org.hibernate.internal.util.StringHelper#unquote(String[], Dialect) if there are no changes to be applied --- .../hibernate/internal/util/StringHelper.java | 27 +++++++++++++---- .../hibernate/test/util/StringHelperTest.java | 29 +++++++++++++++++++ 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/internal/util/StringHelper.java b/hibernate-core/src/main/java/org/hibernate/internal/util/StringHelper.java index c3a8ad0aee..e9d56cd264 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/util/StringHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/util/StringHelper.java @@ -736,15 +736,32 @@ public final class StringHelper { * * @return The unquoted versions. */ - public static String[] unquote(String[] names, Dialect dialect) { + public static String[] unquote(final String[] names, final Dialect dialect) { if ( names == null ) { return null; } - String[] unquoted = new String[names.length]; - for ( int i = 0; i < names.length; i++ ) { - unquoted[i] = unquote( names[i], dialect ); + int failedIndex = -1; + final int length = names.length; + for ( int i = 0; i < length; i++ ) { + if ( isQuoted( names[i], dialect ) ) { + failedIndex = i; + break; + } + } + if ( failedIndex == -1 ) { + //In this case all strings are already unquoted, so return the same array as the input: + //this is a good optimisation to skip an array copy as typically either all names are consistently quoted, or none are; + //yet for safety we need to deal with mixed scenarios as well. + return names; + } + else { + String[] unquoted = new String[length]; + System.arraycopy( names, 0, unquoted, 0, failedIndex ); + for ( int i = failedIndex; i < length; i++ ) { + unquoted[i] = unquote( names[i], dialect ); + } + return unquoted; } - return unquoted; } diff --git a/hibernate-core/src/test/java/org/hibernate/test/util/StringHelperTest.java b/hibernate-core/src/test/java/org/hibernate/test/util/StringHelperTest.java index bec3ebef07..f3009a6b88 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/util/StringHelperTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/util/StringHelperTest.java @@ -6,18 +6,24 @@ */ package org.hibernate.test.util; +import java.util.Arrays; + +import org.junit.Assert; import org.junit.Test; +import org.hibernate.dialect.H2Dialect; import org.hibernate.internal.util.StringHelper; import org.hibernate.testing.junit4.BaseUnitTestCase; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; /** * @author Steve Ebersole */ public class StringHelperTest extends BaseUnitTestCase { + private static final String BASE_PACKAGE = "org.hibernate"; private static final String STRING_HELPER_FQN = "org.hibernate.internal.util.StringHelper"; private static final String STRING_HELPER_NAME = StringHelper.unqualify( STRING_HELPER_FQN ); @@ -54,4 +60,27 @@ public class StringHelperTest extends BaseUnitTestCase { assertEquals( StringHelper.indexOfIdentifierWord( "no identifier here", "?1" ), -1 ); assertEquals( StringHelper.indexOfIdentifierWord( "some text ?", "?" ), 10 ); } + + private static H2Dialect DIALECT = new H2Dialect(); + @Test + public void testArrayUnquoting() { + assertNull( StringHelper.unquote( (String[]) null, DIALECT ) ); + //This to verify that the string array isn't being copied unnecessarily: + unchanged( new String [0] ); + unchanged( new String[] { "a" } ); + unchanged( new String[] { "a", "b" } ); + helperEquals( new String[] { "a", "b", "c" }, new String[] { "a", "b", "`c`" } ); + helperEquals( new String[] { "a", "b", "c" }, new String[] { "a", "\"b\"", "c" } ); + } + + private static void unchanged(String[] input) { + final String[] output = StringHelper.unquote( input, DIALECT ); + assertTrue( input == output ); + } + + private static void helperEquals(String[] expectation, String[] input) { + final String[] output = StringHelper.unquote( input, DIALECT ); + assertTrue( Arrays.equals( expectation, output ) ); + } + }