HHH-2403 - Improved import.sql

This commit is contained in:
Lukasz Antoniak 2011-11-06 13:51:40 +01:00 committed by Steve Ebersole
parent ebd24bbc87
commit c6d616a8bf
7 changed files with 186 additions and 29 deletions

View File

@ -0,0 +1,83 @@
header
{
package org.hibernate.hql.internal.antlr;
import java.util.List;
import java.util.LinkedList;
}
/**
* Lexer and parser used to extract single statements from import SQL script. Supports single and multiple line
* instructions/comments and quoted strings. Each statement should end with semicolon.
*
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
class SqlStatementParser extends Parser;
options {
buildAST = false;
}
{
/** 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) {
current.append( stmt );
}
protected void out(Token token) {
out( token.getText() );
}
public List<String> getStatementList() {
return statementList;
}
protected void statementEnd() {
statementList.add( current.toString().trim() );
current = new StringBuilder();
}
}
script
: ( statement )*
;
statement
: ( s:NOT_STMT_END { out( s ); } | q:QUOTED_STRING { out( q ); } )* STMT_END { statementEnd(); }
;
class SqlStatementLexer extends Lexer;
options {
k = 2;
charVocabulary = '\u0000'..'\uFFFE';
}
STMT_END
: ';'
;
NOT_STMT_END
: ~( ';' )
;
QUOTED_STRING
: '\'' ( (ESCqs)=> ESCqs | ~'\'' )* '\''
;
protected
ESCqs
: '\'' '\''
;
LINE_COMMENT
: ( "//" | "--" ) ( ~('\n'|'\r') )* { $setType(Token.SKIP); }
;
MULTILINE_COMMENT
: "/*" ( options {greedy=false;} : . )* "*/" { $setType(Token.SKIP); }
;

View File

@ -39,6 +39,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import org.hibernate.internal.util.StringHelper;
import org.jboss.logging.Logger;
import org.hibernate.HibernateException;
@ -418,29 +419,19 @@ public class SchemaExport {
private void importScript(NamedReader namedReader, List<Exporter> exporters) throws Exception {
BufferedReader reader = new BufferedReader( namedReader.getReader() );
long lineNo = 0;
for ( String sql = reader.readLine(); sql != null; sql = reader.readLine() ) {
try {
lineNo++;
String trimmedSql = sql.trim();
if ( trimmedSql.length() == 0 ||
trimmedSql.startsWith( "--" ) ||
trimmedSql.startsWith( "//" ) ||
trimmedSql.startsWith( "/*" ) ) {
continue;
}
if ( trimmedSql.endsWith(";") ) {
trimmedSql = trimmedSql.substring(0, trimmedSql.length() - 1);
}
LOG.debugf( trimmedSql );
for ( Exporter exporter: exporters ) {
if ( exporter.acceptsImportScripts() ) {
exporter.export( trimmedSql );
List<String> statementList = new StatementExtractor().retrieveStatements( reader );
for ( String statement : statementList ) {
if ( !StringHelper.isEmpty( statement ) ) {
try {
for ( Exporter exporter : exporters ) {
if ( exporter.acceptsImportScripts() ) {
exporter.export( statement );
}
}
}
}
catch ( Exception e ) {
throw new ImportScriptException( "Error during import script execution at line " + lineNo, e );
catch ( Exception e ) {
throw new ImportScriptException( "Error during statement execution (file: '" + namedReader.getName() + "'): " + statement, e );
}
}
}
}

View File

@ -0,0 +1,31 @@
package org.hibernate.tool.hbm2ddl;
import org.hibernate.hql.internal.antlr.SqlStatementLexer;
import org.hibernate.hql.internal.antlr.SqlStatementParser;
import java.io.Reader;
import java.util.List;
/**
* Class responsible for extracting SQL statements from import script. Supports single and multiple line
* instructions/comments and quoted strings.
*
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
public class StatementExtractor {
/**
* @param reader Character stream reader of entire SQL script. Each statement should end with semicolon.
* @return List of single SQL statements (each without semicolon at the end).
*/
List<String> retrieveStatements(final Reader reader) {
final SqlStatementLexer lexer = new SqlStatementLexer( reader );
final SqlStatementParser parser = new SqlStatementParser( lexer );
try {
parser.script(); // Parse script.
}
catch ( Exception e ) {
throw new ImportScriptException( "Error during import script parsing.", e );
}
return parser.getStatementList();
}
}

View File

@ -22,6 +22,7 @@
* Boston, MA 02110-1301 USA
*/
package org.hibernate.test.importfile;
import java.math.BigInteger;
import java.util.List;
import org.junit.Test;
@ -33,14 +34,16 @@ import org.hibernate.cfg.Environment;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
/**
* @author Emmanuel Bernard
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
public class ImportFileTest extends BaseCoreFunctionalTestCase {
@Override
public void configure(Configuration cfg) {
cfg.setProperty( Environment.HBM2DDL_IMPORT_FILES, "/humans.sql,/dogs.sql" );
cfg.setProperty( Environment.HBM2DDL_IMPORT_FILES, "/humans.sql,/dogs.sql,/multiline-stmt.sql" );
}
@Override
@ -52,7 +55,7 @@ public class ImportFileTest extends BaseCoreFunctionalTestCase {
}
@Test
public void testImportFile() throws Exception {
public void testSingleLineImportFile() throws Exception {
Session s = openSession( );
final Transaction tx = s.beginTransaction();
final List<?> humans = s.createQuery( "from " + Human.class.getName() ).list();
@ -69,4 +72,22 @@ public class ImportFileTest extends BaseCoreFunctionalTestCase {
tx.commit();
s.close();
}
@Test
public void testMultipleLineImportFile() throws Exception {
Session s = openSession();
final Transaction tx = s.beginTransaction();
BigInteger count = (BigInteger) s.createSQLQuery( "SELECT COUNT(*) FROM test_data" ).uniqueResult();
assertEquals( "incorrect row number", 3L, count.longValue() );
String multilineText = (String) s.createSQLQuery( "SELECT text FROM test_data WHERE id = 2" ).uniqueResult();
assertEquals( "multiline string inserted incorrectly", "Multiline comment line 1\r\n-- line 2'\r\n/* line 3 */", multilineText );
String empty = (String) s.createSQLQuery( "SELECT text FROM test_data WHERE id = 3" ).uniqueResult();
assertNull( "NULL value inserted incorrectly", empty );
tx.commit();
s.close();
}
}

View File

@ -1,3 +1,3 @@
INSERT INTO dog (id, master_fk) VALUES (1,1)
INSERT INTO dog (id, master_fk) VALUES (2,2)
INSERT INTO dog (id, master_fk) VALUES (3,3)
INSERT INTO dog (id, master_fk) VALUES (1,1);
INSERT INTO dog (id, master_fk) VALUES (2,2);
INSERT INTO dog (id, master_fk) VALUES (3,3);

View File

@ -1,3 +1,3 @@
INSERT INTO human (id, fname, lname) VALUES (1,'Emmanuel','Bernard')
INSERT INTO human (id, fname, lname) VALUES (2,'Gavin','King')
INSERT INTO human (id, fname, lname) VALUES (3,'Max','Andersen')
INSERT INTO human (id, fname, lname) VALUES (1,'Emmanuel','Bernard');
INSERT INTO human (id, fname, lname) VALUES (2,'Gavin','King');
INSERT INTO human (id, fname, lname) VALUES (3,'Max','Andersen');

View File

@ -0,0 +1,31 @@
-- Sample file used to test import feature of multiline SQL script (HHH-2403).
-- Contains various SQL instructions with comments.
CREATE TABLE test_data (
id NUMBER NOT NULL PRIMARY KEY -- primary key
, text VARCHAR2(100) /* any other data */
);
INSERT INTO test_data VALUES (1, 'sample');
DELETE
FROM test_data;
/*
* Data insertion...
*/
INSERT INTO test_data VALUES (2, 'Multiline comment line 1
-- line 2''
/* line 3 */');
/* Invalid insert: INSERT INTO test_data VALUES (1, NULL); */
-- INSERT INTO test_data VALUES (1, NULL);
INSERT INTO test_data VALUES (3 /* 'third record' */, NULL /* value */); -- with NULL value
INSERT INTO test_data (id, text)
VALUES
(
4 -- another record
, NULL
);