Skip to content

Commit

Permalink
HHH-15665 - Fix and added test for issue
Browse files Browse the repository at this point in the history
Signed-off-by: Jan Schatteman <[email protected]>
  • Loading branch information
jrenaat authored and beikov committed Feb 3, 2023
1 parent 1078caa commit 38ec412
Show file tree
Hide file tree
Showing 3 changed files with 173 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,64 @@ public static Identifier toIdentifier(String text, boolean quote) {
}
}

/**
* Means to generate an {@link Identifier} instance from its simple text form.
* <p>
* If passed text is {@code null}, {@code null} is returned.
* <p>
* If passed text is surrounded in quote markers, the generated Identifier
* is considered quoted. Quote markers include back-ticks (`),
* double-quotes (") and brackets ([ and ]).
*
* @param text The text form
* @param quote Whether to quote unquoted text forms
* @param quoteOnNonIdentifierChar Controls whether to treat the result as quoted if text contains characters that are invalid for identifiers
*
* @return The identifier form, or {@code null} if text was {@code null}
*/
public static Identifier toIdentifier(String text, boolean quote, boolean quoteOnNonIdentifierChar) {
if ( StringHelper.isEmpty( text ) ) {
return null;
}
int start = 0;
int end = text.length();
while ( start < end ) {
if ( !Character.isWhitespace( text.charAt( start ) ) ) {
break;
}
start++;
}
while ( start < end ) {
if ( !Character.isWhitespace( text.charAt( end - 1 ) ) ) {
break;
}
end--;
}
if ( isQuoted( text, start, end ) ) {
start++;
end--;
quote = true;
}
else if ( quoteOnNonIdentifierChar && !quote ) {
// Check the letters to determine if we must quote the text
char c = text.charAt( start );
if ( !Character.isLetter( c ) && c != '_' ) {
// SQL identifiers must begin with a letter or underscore
quote = true;
}
else {
for ( int i = start + 1; i < end; i++ ) {
c = text.charAt( i );
if ( !Character.isLetterOrDigit( c ) && c != '_' ) {
quote = true;
break;
}
}
}
}
return new Identifier( text.substring( start, end ), quote );
}

/**
* Is the given identifier text considered quoted. The following patterns are
* recognized as quoted:<ul>
Expand All @@ -96,6 +154,20 @@ public static boolean isQuoted(String name) {
|| ( name.startsWith( "\"" ) && name.endsWith( "\"" ) );
}

public static boolean isQuoted(String name, int start, int end) {
if ( start + 2 < end ) {
switch ( name.charAt( start ) ) {
case '`':
return name.charAt( end - 1 ) == '`';
case '[':
return name.charAt( end - 1 ) == ']';
case '"':
return name.charAt( end - 1 ) == '"';
}
}
return false;
}

/**
* Constructs an identifier instance.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import java.util.Collections;
import java.util.List;

import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.boot.model.relational.QualifiedSequenceName;
import org.hibernate.engine.jdbc.env.spi.IdentifierHelper;
import org.hibernate.tool.schema.extract.spi.ExtractionContext;
Expand All @@ -28,7 +29,7 @@ public class SequenceInformationExtractorMariaDBDatabaseImpl extends SequenceInf

// SQL to get metadata from individual sequence
private static final String SQL_SEQUENCE_QUERY =
"SELECT '%1$s' as sequence_name, minimum_value, maximum_value, start_value, increment, cache_size FROM %1$s ";
"SELECT '%1$s' as sequence_name, minimum_value, maximum_value, start_value, increment, cache_size FROM %2$s ";

private static final String UNION_ALL =
"UNION ALL ";
Expand Down Expand Up @@ -56,7 +57,7 @@ public Iterable<SequenceInformation> extractMetadata(ExtractionContext extractio
if ( sequenceInfoQueryBuilder.length() > 0 ) {
sequenceInfoQueryBuilder.append( UNION_ALL );
}
sequenceInfoQueryBuilder.append( String.format( SQL_SEQUENCE_QUERY, sequenceName ) );
sequenceInfoQueryBuilder.append( String.format( SQL_SEQUENCE_QUERY, sequenceName, Identifier.toIdentifier( sequenceName, false, true ) ) );
}
return extractionContext.getQueryResults(
sequenceInfoQueryBuilder.toString(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package org.hibernate.test.dialect.functional;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.stream.StreamSupport;

import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.MariaDBDialect;
import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorMariaDBDatabaseImpl;
import org.hibernate.tool.schema.extract.spi.ExtractionContext;
import org.hibernate.tool.schema.extract.spi.SequenceInformation;
import org.hibernate.testing.RequiresDialect;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;

import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;

import static org.hibernate.testing.transaction.TransactionUtil.doInAutoCommit;

/**
* @author Jan Schatteman
*/
@RequiresDialect(value = MariaDBDialect.class)
public class MariaDBExtractSequenceInformationTest extends BaseCoreFunctionalTestCase {

private final static String hhh15665SeqName = "HHH-15665-seq";

private final static Map<String, Object> settings = new HashMap<>(3);

static {
settings.put( AvailableSettings.URL, Environment.getProperties().getProperty( AvailableSettings.URL ) );
settings.put( AvailableSettings.USER, Environment.getProperties().getProperty( AvailableSettings.USER ) );
settings.put( AvailableSettings.PASS, Environment.getProperties().getProperty( AvailableSettings.PASS ) );
}

@BeforeClass
public static void setUp() throws Exception {
doInAutoCommit( settings, "CREATE SEQUENCE IF NOT EXISTS `" + hhh15665SeqName + "`" );
}

@AfterClass
public static void tearDown() throws SQLException {
doInAutoCommit( settings, "DROP SEQUENCE IF EXISTS `" + hhh15665SeqName + "`" );
}

@Test
@TestForIssue( jiraKey = "HHH-15665" )
public void testExtractSequenceInformationForSqlServerWithCaseSensitiveCollation() {
StandardServiceRegistry ssr = new StandardServiceRegistryBuilder().applySettings( settings ).build();
JdbcEnvironment jdbcEnvironment = ssr.getService( JdbcEnvironment.class );
JdbcConnectionAccess bootstrapJdbcConnectionAccess = ssr.getService( JdbcServices.class ).getBootstrapJdbcConnectionAccess();

try ( Connection connection = bootstrapJdbcConnectionAccess.obtainConnection() ) {
Iterable<SequenceInformation> sequenceInformations = SequenceInformationExtractorMariaDBDatabaseImpl.INSTANCE.extractMetadata(
new ExtractionContext.EmptyExtractionContext() {
@Override
public Connection getJdbcConnection() {
return connection;
}

@Override
public JdbcEnvironment getJdbcEnvironment() {
return jdbcEnvironment;
}
} );

Assert.assertNotNull( sequenceInformations );

Optional<SequenceInformation> seq = StreamSupport.stream( sequenceInformations.spliterator(), false )
.filter(
sequence -> hhh15665SeqName.equals( sequence.getSequenceName()
.getSequenceName()
.getText() )
)
.findFirst();

Assert.assertTrue( hhh15665SeqName + " not found", seq.isPresent() );
}
catch ( SQLException e ) {
Assert.fail( "Sequence information for " + hhh15665SeqName + " was not retrieved: " + e.getMessage() );
}
finally {
StandardServiceRegistryBuilder.destroy( ssr );
}
}
}

0 comments on commit 38ec412

Please sign in to comment.