HHH-14033 - SQL script parsing problem with multi-line comments

- Better handling of multi-line comments
- Restructured some internal classes to consolidate packages
- Added "system"-style SchemaToolingLogging
This commit is contained in:
Steve Ebersole 2020-05-19 12:25:06 -05:00
parent e1b1207d30
commit b658e903d7
11 changed files with 412 additions and 286 deletions

View File

@ -203,6 +203,9 @@ xjc {
} }
} }
generateGrammarSource {
arguments += "-traceParser"
}
//sourceSets.main.sourceGeneratorsTask.dependsOn xjc //sourceSets.main.sourceGeneratorsTask.dependsOn xjc
//sourceSets.main.sourceGeneratorsTask.dependsOn generateGrammarSource //sourceSets.main.sourceGeneratorsTask.dependsOn generateGrammarSource

View File

@ -1,6 +1,6 @@
header header
{ {
package org.hibernate.hql.internal.antlr; package org.hibernate.tool.schema.ast;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
@ -14,139 +14,136 @@ import org.hibernate.hql.internal.ast.ErrorReporter;
* *
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com) * @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/ */
class SqlStatementParser extends Parser; class GeneratedSqlScriptParser extends Parser;
options { options {
buildAST = false; buildAST = false;
k=3;
} }
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Semantic actions
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
{ {
private ErrorHandler errorHandler = new ErrorHandler();
@Override
public void reportError(RecognitionException e) {
errorHandler.reportError( e );
}
@Override
public void reportError(String s) {
errorHandler.reportError( s );
}
@Override
public void reportWarning(String s) {
errorHandler.reportWarning( s );
}
public void throwExceptionIfErrorOccurred() {
if ( errorHandler.hasErrors() ) {
String errorMessage = errorHandler.getErrorMessage();
if(errorMessage.contains("expecting STMT_END")) {
throw new StatementParserException( "Import script Sql statements must terminate with a ';' char" );
}
throw new StatementParserException( errorHandler.getErrorMessage() );
}
}
/** List of all SQL statements. */
private List<String> statementList = new LinkedList<String>();
/** Currently processing SQL statement. */
private StringBuilder current = new StringBuilder();
protected void out(String stmt) { protected void out(String stmt) {
current.append( stmt ); // by default, nothing to do
} }
protected void out(Token token) { protected void out(Token token) {
out( token.getText() ); // by default, nothing to do
} }
public List<String> getStatementList() { protected void statementStarted() {
return statementList; // by default, nothing to do
} }
protected void statementEnd() { protected void statementEnded() {
statementList.add( current.toString().trim() ); // by default, nothing to do
current = new StringBuilder();
}
public class StatementParserException extends RuntimeException {
public StatementParserException(String message) {
super( message );
}
}
private class ErrorHandler implements ErrorReporter {
private List<String> errorList = new LinkedList<String>();
@Override
public void reportError(RecognitionException e) {
reportError( e.toString() );
}
@Override
public void reportError(String s) {
errorList.add( s );
}
@Override
public void reportWarning(String s) {
}
public boolean hasErrors() {
return !errorList.isEmpty();
}
public String getErrorMessage() {
StringBuilder buf = new StringBuilder();
for ( Iterator iterator = errorList.iterator(); iterator.hasNext(); ) {
buf.append( (String) iterator.next() );
if ( iterator.hasNext() ) {
buf.append( "\n" );
}
}
return buf.toString();
}
} }
} }
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Parser rules
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
script script
: ( statement )* : (statement)+ EOF
; ;
statement statement
: ( s:NOT_STMT_END { out( s ); } | q:QUOTED_STRING { out( q ); } )* STMT_END { statementEnd(); } : { statementStarted(); } (statementPart)* DELIMITER { statementEnded(); }
; ;
class SqlStatementLexer extends Lexer; statementPart
: quotedString
| nonSkippedChar
;
quotedString
: q:QUOTED_TEXT {
out( q );
}
;
nonSkippedChar
: c:CHAR {
out( c );
}
;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Lexer rules
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class SqlScriptLexer extends Lexer;
options { options {
k = 2; k = 2;
charVocabulary = '\u0000'..'\uFFFE'; charVocabulary = '\u0000'..'\uFFFE';
} }
STMT_END DELIMITER : ';' ;
: ';' ( '\t' | ' ' | '\r' | '\n' )*
;
NOT_STMT_END // NOTE : The `ESCqs` part in the match is meant to an escaped quote (two single-quotes) and
: ~( ';' ) // add it to the recognized text. The `(ESCqs) => ESCqs` syntax is a syntactic predicate.
; // We basically give precedence to the two single-quotes as a group as opposed to the first of them
// matching the terminal single-quote. Both single-quotes end up in the quoted text
QUOTED_STRING QUOTED_TEXT
: '\'' ( (ESCqs)=> ESCqs | ~'\'' )* '\'' : '`' ( ~('`') )* '`'
| '\'' ( (ESCqs) => ESCqs | ~('\'') )* '\''
// : '\'' ( ~('\'') )* '\''
; ;
protected protected
ESCqs ESCqs : '\'' '\'' ;
: '\'' '\''
CHAR
: ( ' ' | '\t' ) => ( ' ' | '\t' )
| ~( ';' | '\n' | '\r' )
;
NEWLINE
: ( '\r' | '\n' | '\r''\n' ) {
newline();
// skip the entire match from the lexer stream
$setType( Token.SKIP );
}
; ;
LINE_COMMENT LINE_COMMENT
: ( "//" | "--" ) ( ~('\n'|'\r') )* { $setType(Token.SKIP); } // match `//` or `--` followed by anything other than \n or \r until NEWLINE
: ("//" | "--") ( ~('\n'|'\r') )* {
// skip the entire match from the lexer stream
$setType( Token.SKIP );
}
; ;
MULTILINE_COMMENT BLOCK_COMMENT
: "/*" ( options {greedy=false;} : . )* "*/" { $setType(Token.SKIP); } : "/*"
( /* '\r' '\n' can be matched in one alternative or by matching
'\r' in one iteration and '\n' in another. I am trying to
handle any flavor of newline that comes in, but the language
that allows both "\r\n" and "\r" and "\n" to all be valid
newline is ambiguous. Consequently, the resulting grammar
must be ambiguous. I'm shutting this warning off.
*/
options {
generateAmbigWarnings=false;
}
: { LA(2)!='/' }? '*'
| '\r' '\n' {newline();}
| '\r' {newline();}
| '\n' {newline();}
| ~('*'|'\n'|'\r')
)*
"*/"
{$setType(Token.SKIP);}
; ;

View File

@ -9,28 +9,20 @@ package org.hibernate.tool.hbm2ddl;
import java.io.Reader; import java.io.Reader;
import java.util.List; import java.util.List;
import org.hibernate.hql.internal.antlr.SqlStatementLexer; import org.hibernate.tool.schema.ast.SqlScriptParser;
import org.hibernate.hql.internal.antlr.SqlStatementParser;
/** /**
* Class responsible for extracting SQL statements from import script. Supports instructions/comments and quoted * Class responsible for extracting SQL statements from import script. Supports instructions/comments and quoted
* strings spread over multiple lines. Each statement must end with semicolon. * strings spread over multiple lines. Each statement must end with semicolon.
* *
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com) * @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
* @author Steve Ebersole
*/ */
public class MultipleLinesSqlCommandExtractor implements ImportSqlCommandExtractor { public class MultipleLinesSqlCommandExtractor implements ImportSqlCommandExtractor {
@Override @Override
public String[] extractCommands(Reader reader) { public String[] extractCommands(Reader reader) {
final SqlStatementLexer lexer = new SqlStatementLexer( reader ); final List<String> commands = SqlScriptParser.extractCommands( reader );
final SqlStatementParser parser = new SqlStatementParser( lexer );
try { return commands.toArray( new String[0] );
parser.script(); // Parse script.
parser.throwExceptionIfErrorOccurred();
}
catch ( Exception e ) {
throw new ImportScriptException( "Error during import script parsing.", e );
}
List<String> statementList = parser.getStatementList();
return statementList.toArray( new String[statementList.size()] );
} }
} }

View File

@ -0,0 +1,25 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.tool.schema;
import org.jboss.logging.Logger;
/**
* @author Steve Ebersole
*/
public class SchemaToolingLogging {
public static final String LOGGER_NAME = "org.hibernate.orm.tooling.schema";
public static final Logger LOGGER = Logger.getLogger( LOGGER_NAME );
public static final String AST_LOGGER_NAME = LOGGER_NAME + ".AST";
public static final Logger AST_LOGGER = Logger.getLogger( AST_LOGGER_NAME );
public static final boolean TRACE_ENABLED = LOGGER.isTraceEnabled();
public static final boolean DEBUG_ENABLED = LOGGER.isDebugEnabled();
public static final boolean AST_TRACE_ENABLED = AST_LOGGER.isTraceEnabled();
}

View File

@ -0,0 +1,178 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.tool.schema.ast;
import java.io.Reader;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.function.Consumer;
import org.hibernate.hql.internal.ast.util.ASTUtil;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.tool.schema.SchemaToolingLogging;
import antlr.RecognitionException;
import antlr.Token;
import antlr.TokenStream;
/**
* @author Steve Ebersole
*/
public class SqlScriptParser extends GeneratedSqlScriptParser {
private static String[] TOKEN_NAMES = ASTUtil.generateTokenNameCache( GeneratedSqlScriptParserTokenTypes .class );
public static List<String> extractCommands(Reader reader) {
final List<String> statementList = new ArrayList<>();
final SqlScriptLexer lexer = new SqlScriptLexer( reader );
final SqlScriptParser parser = new SqlScriptParser( statementList::add, lexer );
parser.parseScript();
return statementList;
}
private final List<String> errorList = new LinkedList<>();
private final Consumer<String> commandConsumer;
private StringBuilder currentStatementBuffer;
public SqlScriptParser(Consumer<String> commandConsumer, TokenStream lexer) {
super( lexer );
this.commandConsumer = commandConsumer;
}
private void parseScript() {
try {
// trigger the top-level grammar rule
script();
}
catch ( Exception e ) {
throw new SqlScriptParserException( "Error during import script parsing.", e );
}
failIfAnyErrors();
}
/**
* Semantic action outputting text to the current statement buffer
*/
@Override
protected void out(String text) {
SchemaToolingLogging.AST_LOGGER.tracef( "Buffering text : %s", text );
currentStatementBuffer.append( text );
}
/**
* Semantic action outputting a token to the current statement buffer
*/
@Override
protected void out(Token token) {
SchemaToolingLogging.AST_LOGGER.tracef( "out( %s(%s) )", TOKEN_NAMES[ token.getType() ], token.getText() );
currentStatementBuffer.append( token.getText() );
}
@Override
protected void statementStarted() {
if ( currentStatementBuffer != null ) {
SchemaToolingLogging.LOGGER.debugf( "`#currentStatementBuffer` was not null at `#statementStart`" );
}
currentStatementBuffer = new StringBuilder();
}
/**
* Semantic action signifying the end of a statement (delimiter recognized)
*/
@Override
protected void statementEnded() {
final String statementText = currentStatementBuffer.toString().trim();
SchemaToolingLogging.LOGGER.debugf( "Import statement : %s", statementText );
commandConsumer.accept( statementText );
currentStatementBuffer = null;
}
private void failIfAnyErrors() {
if ( errorList.isEmpty() ) {
return;
}
throw new SqlScriptParserException( buildErrorMessage() );
}
public String buildErrorMessage() {
final StringBuilder buf = new StringBuilder();
for ( int i = 0; i < errorList.size(); i++ ) {
buf.append( errorList.get( i ) );
if ( i < errorList.size() - 1 ) {
buf.append( System.lineSeparator() );
}
}
return buf.toString();
}
@Override
public void reportError(RecognitionException e) {
final String textBase = "RecognitionException(@" + e.getLine() + ":" + e.getColumn() + ")";
String message = e.toString();
if ( message.contains( "expecting DELIMITER" ) ) {
message = "Import script Sql statements must terminate with a ';' char";
}
errorList.add( textBase + " : " + message );
}
@Override
public void reportError(String message) {
if ( message.contains( "expecting DELIMITER" ) ) {
message = "Import script Sql statements must terminate with a ';' char";
}
errorList.add( message );
}
@Override
public void reportWarning(String message) {
SchemaToolingLogging.LOGGER.debugf( "SqlScriptParser recognition warning : " + message );
}
// handle trace logging ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
private final int depthIndent = 2;
private int traceDepth;
@Override
public void traceIn(String ruleName) {
if ( ! SchemaToolingLogging.AST_TRACE_ENABLED ) {
return;
}
if ( inputState.guessing > 0 ) {
return;
}
final String prefix = StringHelper.repeat( '-', ( traceDepth++ * depthIndent ) );
SchemaToolingLogging.AST_LOGGER.tracef( "%s-> %s", prefix, ruleName );
}
@Override
public void traceOut(String ruleName) {
if ( ! SchemaToolingLogging.AST_TRACE_ENABLED ) {
return;
}
if ( inputState.guessing > 0 ) {
return;
}
final String prefix = StringHelper.repeat( '-', ( --traceDepth * depthIndent ) );
SchemaToolingLogging.AST_LOGGER.tracef( "<-%s %s", prefix, ruleName );
}
}

View File

@ -0,0 +1,22 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.tool.schema.ast;
import org.hibernate.HibernateException;
/**
* @author Steve Ebersole
*/
public class SqlScriptParserException extends HibernateException {
public SqlScriptParserException(String message) {
super( message );
}
public SqlScriptParserException(String message, Throwable cause) {
super( message, cause );
}
}

View File

@ -1,38 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.test.fileimport;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.tool.hbm2ddl.ImportSqlCommandExtractor;
import org.hibernate.tool.hbm2ddl.MultipleLinesSqlCommandExtractor;
import org.hibernate.testing.RequiresDialect;
import org.hibernate.testing.TestForIssue;
/**
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
@TestForIssue( jiraKey = "HHH-2403" )
@RequiresDialect(value = H2Dialect.class,
jiraKey = "HHH-6286",
comment = "Only running the tests against H2, because the sql statements in the import file are not generic. " +
"This test should actually not test directly against the db")
public class CommandExtractorServiceTest extends MultiLineImportFileTest {
@Override
public void configure(Configuration cfg) {
cfg.setProperty( Environment.HBM2DDL_IMPORT_FILES, "/org/hibernate/test/fileimport/multi-line-statements.sql" );
}
@Override
protected void prepareBasicRegistryBuilder(StandardServiceRegistryBuilder serviceRegistryBuilder) {
super.prepareBasicRegistryBuilder( serviceRegistryBuilder );
serviceRegistryBuilder.addService( ImportSqlCommandExtractor.class, new MultipleLinesSqlCommandExtractor() );
}
}

View File

@ -0,0 +1,59 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.test.fileimport;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import org.hibernate.tool.hbm2ddl.MultipleLinesSqlCommandExtractor;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.CoreMatchers.startsWith;
import static org.hamcrest.MatcherAssert.assertThat;
/**
* @author Steve Ebersole
*/
public class MultiLineImportExtractorTest {
public static final String IMPORT_FILE = "org/hibernate/test/fileimport/multi-line-statements.sql";
private final MultipleLinesSqlCommandExtractor extractor = new MultipleLinesSqlCommandExtractor();
@Test
public void testExtraction() throws IOException {
final ClassLoader classLoader = ClassLoader.getSystemClassLoader();
try ( final InputStream stream = classLoader.getResourceAsStream( IMPORT_FILE ) ) {
assertThat( stream, notNullValue() );
try ( final InputStreamReader reader = new InputStreamReader( stream ) ) {
final String[] commands = extractor.extractCommands( reader );
assertThat( commands, notNullValue() );
assertThat( commands.length, is( 6 ) );
assertThat( commands[0], startsWith( "CREATE TABLE test_data" ) );
assertThat( commands[1], is( "INSERT INTO test_data VALUES (1, 'sample')" ) );
assertThat( commands[2], is( "DELETE FROM test_data" ) );
assertThat( commands[3], startsWith( "INSERT INTO test_data VALUES (2," ) );
assertThat( commands[3], containsString( "-- line 2" ) );
assertThat( commands[4], startsWith( "INSERT INTO test_data VALUES (3" ) );
assertThat( commands[4], not( containsString( "third record" ) ) );
assertThat( commands[5], containsString( "INSERT INTO test_data (id, text)" ) );
}
}
}
}

View File

@ -6,46 +6,22 @@
*/ */
package org.hibernate.test.fileimport; package org.hibernate.test.fileimport;
import java.util.EnumSet; import java.io.IOException;
import java.util.Map; import java.io.InputStream;
import java.io.InputStreamReader;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
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.H2Dialect; import org.hibernate.dialect.H2Dialect;
import org.hibernate.engine.config.spi.ConfigurationService;
import org.hibernate.hql.internal.antlr.SqlStatementParser;
import org.hibernate.resource.transaction.backend.jta.internal.JtaTransactionCoordinatorBuilderImpl;
import org.hibernate.resource.transaction.spi.TransactionCoordinatorBuilder;
import org.hibernate.tool.hbm2ddl.ImportScriptException;
import org.hibernate.tool.hbm2ddl.MultipleLinesSqlCommandExtractor; import org.hibernate.tool.hbm2ddl.MultipleLinesSqlCommandExtractor;
import org.hibernate.tool.schema.SourceType; import org.hibernate.tool.schema.ast.SqlScriptParserException;
import org.hibernate.tool.schema.TargetType;
import org.hibernate.tool.schema.internal.ExceptionHandlerLoggedImpl;
import org.hibernate.tool.schema.internal.SchemaCreatorImpl;
import org.hibernate.tool.schema.spi.ExceptionHandler;
import org.hibernate.tool.schema.spi.ExecutionOptions;
import org.hibernate.tool.schema.spi.SchemaCreator;
import org.hibernate.tool.schema.spi.ScriptSourceInput;
import org.hibernate.tool.schema.spi.ScriptTargetOutput;
import org.hibernate.tool.schema.spi.SourceDescriptor;
import org.hibernate.tool.schema.spi.TargetDescriptor;
import org.hibernate.testing.RequiresDialect; import org.hibernate.testing.RequiresDialect;
import org.hibernate.testing.TestForIssue; import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.jta.TestingJtaBootstrap;
import org.hibernate.testing.junit4.BaseUnitTestCase; import org.hibernate.testing.junit4.BaseUnitTestCase;
import org.hibernate.test.schemaupdate.CommentGenerationTest;
import org.junit.After;
import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.CoreMatchers.endsWith;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
/** /**
@ -56,120 +32,27 @@ import static org.junit.Assert.fail;
jiraKey = "HHH-6286", jiraKey = "HHH-6286",
comment = "Only running the tests against H2, because the sql statements in the import file are not generic. " + comment = "Only running the tests against H2, because the sql statements in the import file are not generic. " +
"This test should actually not test directly against the db") "This test should actually not test directly against the db")
public class StatementsWithoutTerminalCharsImportFileTest extends BaseUnitTestCase implements ExecutionOptions { public class StatementsWithoutTerminalCharsImportFileTest extends BaseUnitTestCase {
private static final String IMPORT_FILE = "org/hibernate/test/fileimport/statements-without-terminal-chars.sql";
private StandardServiceRegistry ssr;
private static final String EXPECTED_ERROR_MESSAGE = "Import script Sql statements must terminate with a ';' char"; private static final String EXPECTED_ERROR_MESSAGE = "Import script Sql statements must terminate with a ';' char";
@Before
public void setUp() {
ssr = new StandardServiceRegistryBuilder()
.applySetting( Environment.HBM2DDL_AUTO, "none" )
.applySetting( Environment.DIALECT, CommentGenerationTest.SupportCommentDialect.class.getName() )
.applySetting(
Environment.HBM2DDL_IMPORT_FILES,
"/org/hibernate/test/fileimport/statements-without-terminal-chars.sql"
).applySetting( AvailableSettings.HBM2DDL_HALT_ON_ERROR, "true" )
.applySetting(
Environment.HBM2DDL_IMPORT_FILES_SQL_EXTRACTOR,
MultipleLinesSqlCommandExtractor.class.getName()
)
.build();
}
@Test @Test
public void testImportFile() { public void testImportFile() throws IOException {
try { final ClassLoader classLoader = ClassLoader.getSystemClassLoader();
final SchemaCreator schemaCreator = new SchemaCreatorImpl( ssr ); final MultipleLinesSqlCommandExtractor extractor = new MultipleLinesSqlCommandExtractor();
schemaCreator.doCreation( try ( final InputStream stream = classLoader.getResourceAsStream( IMPORT_FILE ) ) {
buildMappings( ssr ), assertThat( stream, notNullValue() );
this, try (final InputStreamReader reader = new InputStreamReader( stream )) {
SourceDescriptorImpl.INSTANCE, extractor.extractCommands( reader );
TargetDescriptorImpl.INSTANCE }
);
fail( "ImportScriptException expected" ); fail( "ImportScriptException expected" );
} }
catch (ImportScriptException e) { catch (SqlScriptParserException e) {
final Throwable cause = e.getCause(); assertThat( e.getMessage(), endsWith( EXPECTED_ERROR_MESSAGE ) );
assertThat( cause, instanceOf( SqlStatementParser.StatementParserException.class ) );
assertThat( cause.getMessage(), is( EXPECTED_ERROR_MESSAGE ) );
} }
} }
@After
public void tearDown() {
if ( ssr != null ) {
StandardServiceRegistryBuilder.destroy( ssr );
}
}
@Override
public Map getConfigurationValues() {
return ssr.getService( ConfigurationService.class ).getSettings();
}
@Override
public boolean shouldManageNamespaces() {
return false;
}
@Override
public ExceptionHandler getExceptionHandler() {
return ExceptionHandlerLoggedImpl.INSTANCE;
}
private static class SourceDescriptorImpl implements SourceDescriptor {
/**
* Singleton access
*/
public static final SourceDescriptorImpl INSTANCE = new SourceDescriptorImpl();
@Override
public SourceType getSourceType() {
return SourceType.METADATA;
}
@Override
public ScriptSourceInput getScriptSourceInput() {
return null;
}
}
private static class TargetDescriptorImpl implements TargetDescriptor {
/**
* Singleton access
*/
public static final TargetDescriptorImpl INSTANCE = new TargetDescriptorImpl();
@Override
public EnumSet<TargetType> getTargetTypes() {
return EnumSet.of( TargetType.DATABASE );
}
@Override
public ScriptTargetOutput getScriptTargetOutput() {
return null;
}
}
private Metadata buildMappings(StandardServiceRegistry registry) {
return new MetadataSources( registry )
.buildMetadata();
}
protected StandardServiceRegistry buildJtaStandardServiceRegistry() {
StandardServiceRegistry registry = TestingJtaBootstrap.prepare().build();
assertThat(
registry.getService( TransactionCoordinatorBuilder.class ),
instanceOf( JtaTransactionCoordinatorBuilderImpl.class )
);
return registry;
}
} }

View File

@ -19,6 +19,9 @@ log4j.rootLogger=info, stdout
log4j.logger.org.hibernate.orm.graph=debug log4j.logger.org.hibernate.orm.graph=debug
#log4j.logger.org.hibernate.orm.tooling.schema=trace
## the AST logger gets very verbose at trace
#log4j.logger.org.hibernate.orm.tooling.schema.AST=debug
log4j.logger.org.hibernate.tool.hbm2ddl=trace log4j.logger.org.hibernate.tool.hbm2ddl=trace
log4j.logger.org.hibernate.testing.cache=debug log4j.logger.org.hibernate.testing.cache=debug

View File

@ -30,3 +30,5 @@ INSERT INTO test_data (id, text)
, NULL , NULL
); );
-- comment;
-- comment;