├── src ├── test │ ├── data │ │ ├── invalid-syntax.sql │ │ ├── drop-test-tables.sql │ │ ├── delimiter-a.sql │ │ ├── delimiter-b.sql │ │ ├── delimiter-c.sql │ │ └── create-test-tables.sql │ ├── resources │ │ └── test.properties │ └── java │ │ └── org │ │ └── codehaus │ │ └── mojo │ │ └── sql │ │ ├── CustomSqlExecMojo.java │ │ ├── SqlSplitterTest.java │ │ └── SqlExecMojoTest.java ├── it │ ├── msql-51 │ │ ├── invoker.properties │ │ ├── derby.properties │ │ └── pom.xml │ ├── msql-9 │ │ ├── src │ │ │ └── main │ │ │ │ └── sql │ │ │ │ └── filter.sql │ │ └── pom.xml │ ├── connection-retry │ │ ├── invoker.properties │ │ └── pom.xml │ ├── msql-64 │ │ ├── src │ │ │ └── main │ │ │ │ └── sql │ │ │ │ ├── sql2.sql │ │ │ │ └── sql1.sql │ │ ├── verify.groovy │ │ └── pom.xml │ ├── setup │ │ ├── invoker.properties │ │ └── pom.xml │ ├── msql-52 │ │ ├── src │ │ │ └── main │ │ │ │ └── sql │ │ │ │ └── oracle-sqlplus.sql │ │ ├── pre-execute.groovy │ │ ├── verify.groovy │ │ └── pom.xml │ ├── settings-security.xml │ ├── derby │ │ ├── src │ │ │ └── test │ │ │ │ └── java │ │ │ │ └── org │ │ │ │ └── codehaus │ │ │ │ └── mojo │ │ │ │ └── sql │ │ │ │ └── QueryTest.java │ │ └── pom.xml │ ├── msql-76 │ │ ├── src │ │ │ └── main │ │ │ │ └── sql │ │ │ │ ├── post-execute.groovy │ │ │ │ └── pre-execute.groovy │ │ ├── verify.groovy │ │ └── pom.xml │ ├── msql-85 │ │ ├── verify.groovy │ │ └── pom.xml │ └── settings.xml ├── main │ ├── resources │ │ └── META-INF │ │ │ └── m2e │ │ │ └── lifecycle-mapping-metadata.xml │ └── java │ │ └── org │ │ └── codehaus │ │ └── mojo │ │ └── sql │ │ ├── Fileset.java │ │ ├── DelimiterType.java │ │ ├── SqlSplitter.java │ │ └── SqlExecMojo.java └── site │ ├── apt │ ├── examples │ │ ├── settings.apt │ │ └── execute.apt.vm │ ├── index.apt │ └── usage.apt.vm │ ├── fml │ └── faq.fml │ └── site.xml ├── .gitignore ├── .github ├── release-drafter.yml ├── workflows │ ├── maven.yml │ └── release-drafter.yml └── dependabot.yml ├── .git-blame-ignore-revs ├── README.md ├── pom.xml └── LICENSE.txt /src/test/data/invalid-syntax.sql: -------------------------------------------------------------------------------- 1 | create table bogus; 2 | 3 | -------------------------------------------------------------------------------- /src/it/msql-51/invoker.properties: -------------------------------------------------------------------------------- 1 | invoker.goals = clean test 2 | -------------------------------------------------------------------------------- /src/it/msql-9/src/main/sql/filter.sql: -------------------------------------------------------------------------------- 1 | select ${one} FROM SYSIBM.SYSDUMMY1; -------------------------------------------------------------------------------- /src/it/connection-retry/invoker.properties: -------------------------------------------------------------------------------- 1 | invoker.goals = clean install 2 | -------------------------------------------------------------------------------- /src/it/msql-64/src/main/sql/sql2.sql: -------------------------------------------------------------------------------- 1 | SELECT COUNT( GROUP_ID ) from GROUPS; 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | .settings 3 | .classpath 4 | .project 5 | *.iml 6 | .idea 7 | 8 | -------------------------------------------------------------------------------- /src/it/msql-51/derby.properties: -------------------------------------------------------------------------------- 1 | derby.connection.requireAuthentication=true 2 | derby.user.me=mine -------------------------------------------------------------------------------- /.github/release-drafter.yml: -------------------------------------------------------------------------------- 1 | _extends: .github 2 | tag-template: sql-maven-plugin-$NEXT_MINOR_VERSION 3 | -------------------------------------------------------------------------------- /.git-blame-ignore-revs: -------------------------------------------------------------------------------- 1 | # code reformat after spotless enabled 2 | 247a02c5c43829b766f038a1dd17d6112be94f25 3 | -------------------------------------------------------------------------------- /src/it/setup/invoker.properties: -------------------------------------------------------------------------------- 1 | invoker.name = Setup Integration Test Parent 2 | invoker.goals = install 3 | -------------------------------------------------------------------------------- /src/test/data/drop-test-tables.sql: -------------------------------------------------------------------------------- 1 | drop table PERSON; 2 | drop table PLACE; 3 | drop table PERSON_PLACE_MAP; 4 | 5 | -------------------------------------------------------------------------------- /src/test/data/delimiter-a.sql: -------------------------------------------------------------------------------- 1 | DELIMITER ¤ 2 | create table DELIM_A ( ID integer )¤ 3 | create table DELIM_A2 ( ID integer )¤ 4 | -------------------------------------------------------------------------------- /src/test/data/delimiter-b.sql: -------------------------------------------------------------------------------- 1 | DELIMITER # 2 | create table DELIM_B ( ID integer )# 3 | create table DELIM_B2 ( ID integer )# 4 | -------------------------------------------------------------------------------- /src/test/data/delimiter-c.sql: -------------------------------------------------------------------------------- 1 | DELIMITER £ 2 | create table DELIM_C ( ID integer )£ 3 | create table DELIM_C2 ( ID integer )£ 4 | -------------------------------------------------------------------------------- /src/it/msql-52/src/main/sql/oracle-sqlplus.sql: -------------------------------------------------------------------------------- 1 | DROP SEQUENCE &&schema..ACCOUNT_CODE_DEFINITION_SEQ; 2 | 3 | SELECT &1 FROM DUAL; -------------------------------------------------------------------------------- /src/it/settings-security.xml: -------------------------------------------------------------------------------- 1 | 2 | {vSyf3GushWgHLQbM0Rzrsy3AbQIlHkUYP8wcNsPWAYU=} 3 | -------------------------------------------------------------------------------- /src/test/resources/test.properties: -------------------------------------------------------------------------------- 1 | driver=org.hsqldb.jdbc.JDBCDriver 2 | user=sa 3 | password= 4 | url=jdbc:hsqldb:mem:egdb 5 | driverProperties=key1=value1,key2=value2 6 | -------------------------------------------------------------------------------- /src/it/msql-64/src/main/sql/sql1.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE GROUPS (GROUP_ID SMALLINT NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 5, INCREMENT BY 5), ADDRESS VARCHAR(100), PHONE VARCHAR(15)); 2 | -------------------------------------------------------------------------------- /.github/workflows/maven.yml: -------------------------------------------------------------------------------- 1 | name: GitHub CI 2 | 3 | on: 4 | push: 5 | pull_request: 6 | 7 | jobs: 8 | build: 9 | name: Verify 10 | uses: apache/maven-gh-actions-shared/.github/workflows/maven-verify.yml@v4 11 | -------------------------------------------------------------------------------- /.github/workflows/release-drafter.yml: -------------------------------------------------------------------------------- 1 | name: Release Drafter 2 | on: 3 | push: 4 | branches: 5 | - master 6 | jobs: 7 | update_release_draft: 8 | uses: apache/maven-gh-actions-shared/.github/workflows/release-drafter.yml@v4 9 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "maven" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | 8 | - package-ecosystem: "github-actions" 9 | directory: "/" 10 | schedule: 11 | interval: "daily" 12 | -------------------------------------------------------------------------------- /src/test/data/create-test-tables.sql: -------------------------------------------------------------------------------- 1 | create table PERSON ( PERSON_ID integer, FIRSTNAME varchar(50), LASTNAME varchar(50) ); 2 | create table PLACE ( PLACE_ID integer, CITY varchar(50), STATE varchar(50) ); 3 | create table PERSON_PLACE_MAP ( PERSON_ID integer, PLACE_ID integer ); 4 | 5 | -------------------------------------------------------------------------------- /src/it/msql-52/pre-execute.groovy: -------------------------------------------------------------------------------- 1 | File outputFile = new File( basedir, 'target/oracle-sqlplus.sql') 2 | outputFile.getParentFile().mkdirs(); 3 | new FileReader( 'src/main/sql/oracle-sqlplus.sql' ).transformLine( outputFile.newWriter() ) { line-> 4 | line.replaceAll( '&1', 'customer' ).replaceAll( '&&schema..', 'SOME_SCHEMA.' ) 5 | } 6 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/m2e/lifecycle-mapping-metadata.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | execute 8 | 9 | 10 | 11 | 12 | 18 | false 19 | false 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/it/derby/src/test/java/org/codehaus/mojo/sql/QueryTest.java: -------------------------------------------------------------------------------- 1 | package org.codehaus.mojo.sql; 2 | 3 | import java.sql.Connection; 4 | import java.sql.Driver; 5 | import java.sql.ResultSet; 6 | import java.sql.Statement; 7 | 8 | import junit.framework.TestCase; 9 | 10 | public class QueryTest 11 | extends TestCase 12 | { 13 | 14 | public void testQuery() 15 | throws Exception 16 | { 17 | Class dc = Class.forName( "org.apache.derby.jdbc.EmbeddedDriver" ); 18 | Driver driverInstance = (Driver) dc.newInstance(); 19 | 20 | Connection conn = driverInstance.connect( "jdbc:derby:target/testdb", null ); 21 | 22 | Statement st = conn.createStatement(); 23 | ResultSet rs = st.executeQuery( "select count(*) from derbyDB" ); 24 | rs.next(); 25 | assertEquals( 2, rs.getInt(1) ); 26 | 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MojoHaus SQL Maven Plugin 2 | 3 | This is the [sql-maven-plugin](http://www.mojohaus.org/sql-maven-plugin/). 4 | 5 | [![Apache License, Version 2.0, January 2004](https://img.shields.io/github/license/mojohaus/sql-maven-plugin.svg?label=License)](http://www.apache.org/licenses/) 6 | [![Maven Central](https://img.shields.io/maven-central/v/org.codehaus.mojo/sql-maven-plugin.svg?label=Maven%20Central)](http://search.maven.org/#search%7Cga%7C1%7Csql-maven-plugin) 7 | [![Build Status](https://travis-ci.org/mojohaus/sql-maven-plugin.svg?branch=master)](https://travis-ci.org/mojohaus/sql-maven-plugin) 8 | 9 | ## Releasing 10 | 11 | * Make sure `gpg-agent` is running. 12 | * Execute `mvn -B release:prepare release:perform` 13 | 14 | For publishing the site do the following: 15 | 16 | ``` 17 | cd target/checkout 18 | mvn verify site site:stage scm-publish:publish-scm 19 | ``` 20 | 21 | -------------------------------------------------------------------------------- /src/it/msql-76/src/main/sql/post-execute.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | assert true -------------------------------------------------------------------------------- /src/it/msql-76/src/main/sql/pre-execute.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | assert true -------------------------------------------------------------------------------- /src/it/msql-85/verify.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | File log = new File(basedir, 'target/logs/maven/sql.log') 20 | assert log.exists() 21 | -------------------------------------------------------------------------------- /src/site/apt/examples/settings.apt: -------------------------------------------------------------------------------- 1 | ------ 2 | Settings 3 | ------ 4 | Dan T. Tran 5 | 6 | ------ 7 | 2010-02-15 8 | ------ 9 | 10 | Settings 11 | 12 | You can hide the username/password in your <<>>. Just ensure that you configure <<>> in your 13 | POM, otherwise it will use your database's URL as a lookup key. 14 | 15 | -------------------- 16 | 17 | [...] 18 | 19 | 20 | sensibleKey 21 | postgres 22 | password 23 | 24 | [...] 25 | 26 | [...] 27 | 28 | -------------------- 29 | 30 | * Encrypted passwords 31 | 32 | Since 1.5 it's also possible to use encrypted passwords the way Maven does. Follow the instruction of the {{{http://maven.apache.org/guides/mini/guide-encryption.html}encryption mini guide}}. 33 | Just like unencrypted passwords you have to be sure to set the <<>>, the plugin will detect if the password is encrypted or not. 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/main/java/org/codehaus/mojo/sql/Fileset.java: -------------------------------------------------------------------------------- 1 | package org.codehaus.mojo.sql; 2 | 3 | /* 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | 22 | /** 23 | * @author Brian Topping 24 | */ 25 | public class Fileset extends org.codehaus.plexus.util.DirectoryScanner {} 26 | -------------------------------------------------------------------------------- /src/it/msql-52/verify.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | File log = new File(basedir, 'target/oracle-sqlplus.sql') 20 | assert log.exists() 21 | assert log.readLines().get(0) == 'DROP SEQUENCE SOME_SCHEMA.ACCOUNT_CODE_DEFINITION_SEQ;' 22 | assert log.readLines().get(2) == 'SELECT customer FROM DUAL;' -------------------------------------------------------------------------------- /src/it/msql-76/verify.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | File log = new File(basedir, 'build.log') 21 | assert log.exists() 22 | assert log.text.contains( '[INFO] run pre-execute script' ) 23 | assert log.text.contains( 'pre-execute.groovy' ) 24 | assert log.text.contains( '[INFO] run post-execute script' ) 25 | assert log.text.contains( 'post-execute.groovy' ) 26 | -------------------------------------------------------------------------------- /src/it/msql-64/verify.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | File log = new File(basedir, 'build.log') 20 | assert log.exists() 21 | assert log.getText().contains('CREATE TABLE GROUPS (GROUP_ID SMALLINT NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 5, INCREMENT BY 5), ADDRESS VARCHAR(100), PHONE VARCHAR(15))') 22 | assert log.getText().contains('SELECT COUNT( GROUP_ID ) from GROUPS') -------------------------------------------------------------------------------- /src/test/java/org/codehaus/mojo/sql/CustomSqlExecMojo.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2024 MojoHaus. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.codehaus.mojo.sql; 17 | 18 | import java.io.PrintStream; 19 | import java.sql.ResultSet; 20 | import java.sql.SQLException; 21 | 22 | public class CustomSqlExecMojo extends SqlExecMojo { 23 | @Override 24 | protected void printResultSet(ResultSet rs, PrintStream out) throws SQLException { 25 | out.println("This is the way"); 26 | } 27 | 28 | @Override 29 | protected void printResultSetCount(int updateCountTotal, PrintStream out) { 30 | out.println(updateCountTotal + " cows affected"); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/site/fml/faq.fml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | When do I have to set the delimiterType? 5 | 6 |

By default the sql-maven-plugin will check if a line contains the specified delimiter, which is by default a semicolon(;). 7 | More complex statements, such as a trigger creation, may contain semi-colons too, although these are not yet the end of the sql-statement. 8 | In such case you have to change the delimiterType to 'row'.
9 | Now the plugin will check if the complete row matches the delimiter, in order to recognize the end of the sql statement. 10 |

11 |

An example when to use <delimiterType>row</delimiterType>: 12 |

13 |  CREATE OR REPLACE FUNCTION my_trig()
14 |  RETURNS "trigger" AS
15 |  $BODY$
16 |    declare 
17 |    t text; 
18 |    begin
19 |     -- any plpgsql code here, where each line ends with a semicolon
20 |    return NEW; 
21 |  end$BODY$
22 |  LANGUAGE 'plpgsql' VOLATILE;   
23 | 
24 | Note: Delimiters within values or comments are not a problem, these will be ignored.
25 | Note: The sql will be parsed until the delimiter or the EOF. 26 |

27 |
28 |
29 |
30 |
-------------------------------------------------------------------------------- /src/it/msql-52/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | 6 | org.codehaus.mojo.it.sql 7 | sql-maven-plugin-parent 8 | 0.1 9 | 10 | 11 | org.codehaus.mojo.sql.it 12 | sql-52 13 | 0.0.1-SNAPSHOT 14 | 15 | 16 | 17 | 18 | org.codehaus.mojo 19 | sql-maven-plugin 20 | @project.version@ 21 | 22 | 23 | org.apache.derby 24 | derby 25 | @derby.version@ 26 | 27 | 28 | 29 | 30 | org.apache.derby.jdbc.EmbeddedDriver 31 | jdbc:derby:${project.build.directory}/sql64db;create=true 32 | pre-execute.groovy 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/site/site.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 20 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/it/msql-85/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | 6 | org.codehaus.mojo.it.sql 7 | sql-maven-plugin-parent 8 | 0.1 9 | 10 | 11 | org.codehaus.mojo.sql.it 12 | msql-85 13 | 0.0.1-SNAPSHOT 14 | 15 | 16 | 17 | 18 | org.codehaus.mojo 19 | sql-maven-plugin 20 | @project.version@ 21 | 22 | 23 | org.apache.derby 24 | derby 25 | @derby.version@ 26 | 27 | 28 | 29 | 30 | org.apache.derby.jdbc.EmbeddedDriver 31 | jdbc:derby:${project.build.directory}/testdb;create=true 32 | select 1 FROM SYSIBM.SYSDUMMY1; 33 | ${project.build.directory}/logs/maven/sql.log 34 | 35 | 36 | 37 | 38 | 39 | 40 | 1 41 | 42 | 43 | -------------------------------------------------------------------------------- /src/it/msql-64/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | 6 | org.codehaus.mojo.it.sql 7 | sql-maven-plugin-parent 8 | 0.1 9 | 10 | 11 | org.codehaus.mojo.sql.it 12 | sql-64 13 | 0.0.1-SNAPSHOT 14 | 15 | 16 | 17 | 18 | org.codehaus.mojo 19 | sql-maven-plugin 20 | @project.version@ 21 | 22 | 23 | org.apache.derby 24 | derby 25 | @derby.version@ 26 | 27 | 28 | 29 | 30 | org.apache.derby.jdbc.EmbeddedDriver 31 | jdbc:derby:${project.build.directory}/sql64db;create=true 32 | 33 | src/main/sql/sql1.sql 34 | src/main/sql/sql2.sql 35 | 36 | 37 | 38 | 39 | 40 | 41 | 1 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /src/it/msql-76/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | 6 | org.codehaus.mojo.it.sql 7 | sql-maven-plugin-parent 8 | 0.1 9 | 10 | 11 | org.codehaus.mojo.sql.it 12 | sql-76 13 | 0.0.1-SNAPSHOT 14 | 15 | 16 | 17 | 18 | org.codehaus.mojo 19 | sql-maven-plugin 20 | @project.version@ 21 | 22 | 23 | org.apache.derby 24 | derby 25 | @derby.version@ 26 | 27 | 28 | 29 | 30 | org.apache.derby.jdbc.EmbeddedDriver 31 | jdbc:derby:${project.build.directory}/sql76db;create=true 32 | select 1 FROM SYSIBM.SYSDUMMY1; 33 | src/main/sql/pre-execute.groovy 34 | src/main/sql/post-execute.groovy 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/it/msql-9/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | 6 | org.codehaus.mojo.it.sql 7 | sql-maven-plugin-parent 8 | 0.1 9 | 10 | 11 | org.codehaus.mojo.sql.it 12 | sql-9 13 | 0.0.1-SNAPSHOT 14 | 15 | 16 | 17 | 18 | org.codehaus.mojo 19 | sql-maven-plugin 20 | @project.version@ 21 | 22 | 23 | org.apache.derby 24 | derby 25 | @derby.version@ 26 | 27 | 28 | 29 | 30 | org.apache.derby.jdbc.EmbeddedDriver 31 | jdbc:derby:${project.build.directory}/testdb;create=true 32 | ${maven.test.skip} 33 | select ${one} FROM SYSIBM.SYSDUMMY1; 34 | true 35 | 36 | src/main/sql/filter.sql 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 1 45 | 46 | 47 | -------------------------------------------------------------------------------- /src/site/apt/index.apt: -------------------------------------------------------------------------------- 1 | ------ 2 | Introduction 3 | ------ 4 | Dan T. Tran 5 | 6 | ------ 7 | 2010-02-15 8 | ------ 9 | 10 | SQL Maven Plugin 11 | 12 | Use this plugin to execute SQL statements in a combination of strings, 13 | a list of files and/or a set of files through <<>>, <<>>, and 14 | <<>> configurations respectively. 15 | 16 | 17 | * Goals Overview 18 | 19 | * {{{./execute-mojo.html}sql:execute}} Execute SQL statements. 20 | 21 | [] 22 | 23 | 24 | * Usage 25 | 26 | General instructions on how to use the SQL Maven Plugin can be found on the {{{./usage.html}usage page}}. 27 | 28 | In case you still have questions regarding the plugin's usage, please feel 29 | free to contact the {{{./mail-lists.html}user mailing list}}. The posts to the mailing list are archived and could 30 | already contain the answer to your question as part of an older thread. Hence, it is also worth browsing/searching 31 | the {{{./mail-lists.html}mail archive}}. 32 | 33 | If you feel like the plugin is missing a feature or has a defect, you can fill a feature request or bug report in our 34 | {{{./issue-tracking.html}issue tracker}}. When creating a new issue, please provide a comprehensive description of your 35 | concern. Especially for fixing bugs it is crucial that the developers can reproduce your problem. For this reason, 36 | entire debug logs, POMs or most preferably little demo projects attached to the issue are very much appreciated. 37 | Of course, patches are most welcome too. Contributors can check out the project from our 38 | {{{./source-repository.html}source repository}} and will find supplementary information in the 39 | {{{http://maven.apache.org/guides/development/guide-helping.html}guide to helping with Maven}}. 40 | 41 | 42 | * Examples 43 | 44 | * {{{./examples/execute.html}Executions.}} 45 | 46 | * {{{./examples/settings.html}Hide username/password in <<>>.}} 47 | 48 | [] 49 | -------------------------------------------------------------------------------- /src/it/settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 21 | 22 | 23 | 24 | 25 | 26 | my.server 27 | me 28 | {iFtD2TFFjzoHEDN1RxW21zEBYW0Gt7GwbsOm6yDS63s=} 29 | 30 | 31 | 32 | 33 | 34 | it-repo 35 | 36 | 37 | local.central 38 | @localRepositoryUrl@ 39 | 40 | true 41 | 42 | 43 | true 44 | 45 | 46 | 47 | 48 | 49 | local.central 50 | @localRepositoryUrl@ 51 | 52 | true 53 | 54 | 55 | true 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | it-repo 64 | 65 | 66 | -------------------------------------------------------------------------------- /src/site/apt/usage.apt.vm: -------------------------------------------------------------------------------- 1 | ------ 2 | Usage 3 | ------ 4 | Dan T. Tran 5 | 6 | ------ 7 | 2010-02-15 8 | ------ 9 | 10 | Usage 11 | 12 | The execution of this plugin's goal can be bound to a phase of the build lifecycle. 13 | 14 | Use the <<<\>>> element inside the <<<\>>> element to specify the artifact that has your 15 | JDBC driver. 16 | 17 | --------------------------- 18 | 19 | [...] 20 | 21 | [...] 22 | 23 | [...] 24 | 25 | org.codehaus.mojo 26 | sql-maven-plugin 27 | ${project.version} 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | [...] 45 | 46 | 47 | 48 | 49 | 50 | 51 | execute 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | [...] 61 | 62 | 63 | 64 | 65 | [...] 66 | 67 | [...] 68 | 69 | 70 | [...] 71 | 72 | [...] 73 | 74 | [...] 75 | 76 | --------------------------- 77 | -------------------------------------------------------------------------------- /src/it/msql-51/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | 6 | org.codehaus.mojo.it.sql 7 | sql-maven-plugin-parent 8 | 0.1 9 | 10 | 11 | org.codehaus.mojo 12 | sql-maven-plugin-test 13 | 0.0.1-SNAPSHOT 14 | 15 | 16 | 17 | 18 | org.codehaus.mojo 19 | sql-maven-plugin 20 | @project.version@ 21 | 22 | 23 | org.apache.derby 24 | derby 25 | @derby.version@ 26 | 27 | 28 | 29 | 30 | 31 | prepare 32 | initialize 33 | 34 | execute 35 | 36 | 37 | jdbc:derby:${project.build.directory}/testdb;create=true 38 | me 39 | mine 40 | CREATE TABLE PEOPLE (PERSON_ID INT NOT NULL GENERATED ALWAYS AS IDENTITY CONSTRAINT PEOPLE_PK PRIMARY KEY, PERSON VARCHAR(26)); 41 | 42 | 43 | 44 | 45 | test 46 | test 47 | 48 | execute 49 | 50 | 51 | jdbc:derby:${project.build.directory}/testdb;create=false 52 | my.server 53 | SELECT * FROM PEOPLE; 54 | 55 | 56 | 57 | 58 | org.apache.derby.jdbc.EmbeddedDriver 59 | 60 | 61 | 62 | 63 | 64 | 65 | 1 66 | 67 | 68 | -------------------------------------------------------------------------------- /src/it/setup/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 4.0.0 8 | 9 | org.codehaus.mojo.it.sql 10 | sql-maven-plugin-parent 11 | 0.1 12 | 13 | pom 14 | 15 | Parent 0.1 16 | 17 | 18 | UTF-8 19 | 20 | 21 | 22 | 23 | 24 | 25 | junit 26 | junit 27 | 4.13.1 28 | test 29 | 30 | 31 | org.testng 32 | testng 33 | 6.8 34 | test 35 | 36 | 37 | log4j 38 | log4j 39 | 1.2.16 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | org.apache.maven.plugins 49 | maven-surefire-plugin 50 | 2.19.1 51 | 52 | 53 | org.apache.maven.plugins 54 | maven-compiler-plugin 55 | 3.5.1 56 | 57 | 58 | org.apache.maven.plugins 59 | maven-clean-plugin 60 | 3.0.0 61 | 62 | 63 | org.apache.maven.plugins 64 | maven-assembly-plugin 65 | 2.4 66 | 67 | 68 | org.apache.maven.plugins 69 | maven-jar-plugin 70 | 3.0.2 71 | 72 | 73 | org.apache.maven.plugins 74 | maven-install-plugin 75 | 2.5.2 76 | 77 | 78 | org.apache.maven.plugins 79 | maven-war-plugin 80 | 2.3 81 | 82 | 83 | org.apache.maven.plugins 84 | maven-resources-plugin 85 | 3.0.1 86 | 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /src/it/connection-retry/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | org.codehaus.mojo.it.sql 7 | sql-maven-plugin-parent 8 | 0.1 9 | 10 | 11 | org.codehaus.mojo 12 | sql-maven-plugin-it-connection-retry 13 | 1.0-SNAPSHOT 14 | 15 | sql-maven-plugin Connection Retry Database Integration Test 16 | 17 | 18 | 19 | org.apache.derby 20 | derby 21 | @derby.version@ 22 | test 23 | 24 | 25 | junit 26 | junit 27 | 4.13.1 28 | test 29 | 30 | 31 | 32 | 33 | 34 | 35 | org.codehaus.mojo 36 | sql-maven-plugin 37 | @project.version@ 38 | 39 | 40 | org.apache.derby 41 | derby 42 | @derby.version@ 43 | 44 | 45 | 46 | org.apache.derby.jdbc.EmbeddedDriver 47 | jdbc:derby:${project.build.directory}/testdb;create=true 48 | 49 | 50 | 51 | 52 | create-table 53 | process-test-resources 54 | 55 | execute 56 | 57 | 58 | 59 | create table retry(num int); 60 | create table another(num int); 61 | 62 | 63 | 64 | 65 | 66 | 67 | insert-data 68 | process-test-resources 69 | 70 | execute 71 | 72 | 73 | 74 | select 1 from retry 75 | select 1 from another 76 | 77 | 2 78 | 2 79 | 80 | insert into retry values (2024); 81 | insert into another values (42); 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /src/it/derby/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | org.codehaus.mojo.it.sql 7 | sql-maven-plugin-parent 8 | 0.1 9 | 10 | 11 | org.codehaus.mojo 12 | sql-maven-plugin-it-derby 13 | 1.0-SNAPSHOT 14 | 15 | sql-maven-plugin Derby Database Integration Test 16 | 17 | 18 | 19 | org.apache.derby 20 | derby 21 | @derby.version@ 22 | test 23 | 24 | 25 | junit 26 | junit 27 | 4.13.1 28 | test 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | org.codehaus.mojo 40 | sql-maven-plugin 41 | @project.version@ 42 | 43 | 44 | 45 | org.apache.derby 46 | derby 47 | @derby.version@ 48 | 49 | 50 | 51 | 52 | org.apache.derby.jdbc.EmbeddedDriver 53 | jdbc:derby:${project.build.directory}/testdb;create=true 54 | ${maven.test.skip} 55 | 56 | 57 | 58 | 59 | 60 | create-table 61 | process-test-resources 62 | 63 | execute 64 | 65 | 66 | create table derbyDB(num int, addr varchar(40)) 67 | 68 | 69 | 70 | 71 | update-table 72 | process-test-resources 73 | 74 | execute 75 | 76 | 77 | 78 | insert into derbyDB values (1956,'Webster St.'); 79 | insert into derbyDB values (1910,'Union St.'); 80 | update derbyDB set num=180, addr='Grand Ave.' where num=1956; 81 | 82 | 83 | 84 | 85 | 86 | shutdown-database-so-that-test-can-run 87 | process-test-resources 88 | 89 | execute 90 | 91 | 92 | jdbc:derby:;shutdown=true 93 | true 94 | 95 | 96 | 97 | 98 | drop-table 99 | test 100 | 101 | execute 102 | 103 | 104 | drop table derbyDB 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | -------------------------------------------------------------------------------- /src/main/java/org/codehaus/mojo/sql/DelimiterType.java: -------------------------------------------------------------------------------- 1 | package org.codehaus.mojo.sql; 2 | 3 | /* 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | 22 | /** 23 | * @author Brian Topping 24 | */ 25 | public class DelimiterType { 26 | public static final String NORMAL = "normal"; 27 | 28 | public static final String ROW = "row"; 29 | 30 | /** 31 | * The selected value in this enumeration. 32 | */ 33 | protected String value; 34 | 35 | /** 36 | * the index of the selected value in the array. 37 | */ 38 | private int index = -1; 39 | 40 | /** 41 | * This is the only method a subclass needs to implement. 42 | * 43 | * @return an array holding all possible values of the enumeration. The order of elements must be fixed so that 44 | * indexOfValue(String) always return the same index for the same value. 45 | */ 46 | public String[] getValues() { 47 | return new String[] {NORMAL, ROW}; 48 | } 49 | 50 | /** bean constructor */ 51 | protected DelimiterType() {} 52 | 53 | /** 54 | * Set the delimiterValue. Use DelimiterType.NORMAL or DelimiterType.ROW 55 | * 56 | * @param value 57 | */ 58 | public final void setValue(String value) { 59 | int index = indexOfValue(value); 60 | if (index == -1) { 61 | throw new IllegalArgumentException(value + " is not a legal value for this attribute"); 62 | } 63 | this.index = index; 64 | this.value = value; 65 | } 66 | 67 | /** 68 | * Is this value included in the enumeration? 69 | * 70 | * @param value 71 | * @return true if this value is supported 72 | */ 73 | public final boolean containsValue(String value) { 74 | return (indexOfValue(value) != -1); 75 | } 76 | 77 | /** 78 | * get the index of a value in this enumeration. 79 | * 80 | * @param value the string value to look for. 81 | * @return the index of the value in the array of strings or -1 if it cannot be found. 82 | * @see #getValues() 83 | */ 84 | public final int indexOfValue(String value) { 85 | String[] values = getValues(); 86 | if (values == null || value == null) { 87 | return -1; 88 | } 89 | for (int i = 0; i < values.length; i++) { 90 | if (value.equals(values[i])) { 91 | return i; 92 | } 93 | } 94 | return -1; 95 | } 96 | 97 | /** 98 | * @return the selected value. 99 | */ 100 | public final String getValue() { 101 | return value; 102 | } 103 | 104 | /** 105 | * @return the index of the selected value in the array. 106 | * @see #getValues() 107 | */ 108 | public final int getIndex() { 109 | return index; 110 | } 111 | 112 | /** 113 | * Convert the value to its string form. 114 | * 115 | * @return the string form of the value. 116 | */ 117 | public String toString() { 118 | return getValue(); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/site/apt/examples/execute.apt.vm: -------------------------------------------------------------------------------- 1 | ------ 2 | Executions 3 | ------ 4 | Dan T. Tran 5 | 6 | ------ 7 | 2010-02-15 8 | ------ 9 | 10 | Executions 11 | 12 | 13 | The following build configuration shows how to drop/create a database and schema, 14 | then populate it before the <<>> phase, and drop the database after the <<>> phase. 15 | 16 | ------------------- 17 | 18 | [...] 19 | 20 | [...] 21 | 22 | 23 | org.codehaus.mojo 24 | sql-maven-plugin 25 | ${project.version} 26 | 27 | 28 | 29 | 30 | postgresql 31 | postgresql 32 | 8.1-407.jdbc3 33 | 34 | 35 | 36 | 37 | 38 | org.postgresql.Driver 39 | jdbc:postgressql://localhost:5432:yourdb 40 | postgres 41 | password 42 | 45 | sensibleKey 46 | 47 | ${maven.test.skip} 48 | 49 | 50 | 51 | 52 | drop-db-before-test-if-any 53 | process-test-resources 54 | 55 | execute 56 | 57 | 58 | 59 | jdbc:postgressql://localhost:5432:bootstrapdb 60 | true 61 | drop database yourdb 62 | 63 | continue 64 | 65 | 66 | 67 | 68 | create-db 69 | process-test-resources 70 | 71 | execute 72 | 73 | 74 | jdbc:postgressql://localhost:5432:yourdb 75 | 76 | true 77 | create database yourdb 78 | 79 | 80 | 81 | 82 | create-schema 83 | process-test-resources 84 | 85 | execute 86 | 87 | 88 | true 89 | 90 | src/main/sql/your-schema.sql 91 | 92 | 93 | 94 | 95 | 96 | create-data 97 | process-test-resources 98 | 99 | execute 100 | 101 | 102 | ascending 103 | 104 | ${basedir} 105 | 106 | src/test/sql/test-data2.sql 107 | src/test/sql/test-data1.sql 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | drop-db-after-test 116 | test 117 | 118 | execute 119 | 120 | 121 | true 122 | drop database yourdb 123 | 124 | 125 | 126 | 127 | [...] 128 | 129 | [...] 130 | 131 | [...] 132 | 133 | ------------------- 134 | -------------------------------------------------------------------------------- /src/main/java/org/codehaus/mojo/sql/SqlSplitter.java: -------------------------------------------------------------------------------- 1 | package org.codehaus.mojo.sql; 2 | 3 | /* 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | 22 | import org.codehaus.plexus.util.StringUtils; 23 | 24 | /** 25 | * Utility class to split a long sql batch script into single SQL commands. 26 | */ 27 | public final class SqlSplitter { 28 | private SqlSplitter() { 29 | // hide utility class constructor 30 | } 31 | 32 | /** 33 | * Value indicating the sql has no end-delimiter like i.e. the semicolon. 34 | */ 35 | public static final int NO_END = -1; 36 | 37 | /** 38 | * parsed sql started a single quote static text which continues on the next line (did not end) 39 | */ 40 | public static final int OVERFLOW_SINGLE_QUOTE = -2; 41 | 42 | /** 43 | * parsed sql started a double quote static text which continues on the next line (did not end) 44 | */ 45 | public static final int OVERFLOW_DOUBLE_QUOTE = -4; 46 | 47 | /** 48 | * parsed sql started a comment with /_* which continues on the next line (did not end) 49 | */ 50 | public static final int OVERFLOW_COMMENT = -8; 51 | 52 | /** 53 | * Check if the given sql line contains a delimiter representing the end of the command. Please note that we do 54 | * not fully parse the SQL, so if we get a malformed statement, we cannot detect it. 55 | * 56 | * @param line to parse 57 | * @param delimiter which should be used to split SQL commands 58 | * @param overflowValue 0=none, {@link SqlSplitter#OVERFLOW_COMMENT}, {@link SqlSplitter#OVERFLOW_SINGLE_QUOTE} or 59 | * {@link SqlSplitter#OVERFLOW_DOUBLE_QUOTE} 60 | * @return position after the end character if the given line contains the end of a SQL script, 61 | * {@link SqlSplitter#NO_END} if it doesn't contain an end char. {@link SqlSplitter#OVERFLOW_SINGLE_QUOTE} 62 | * will be returned if a single quote didn't get closed, {@link SqlSplitter#OVERFLOW_DOUBLE_QUOTE} likewise 63 | * for not closed double quotes. 64 | */ 65 | public static int containsSqlEnd(String line, String delimiter, final int overflowValue) { 66 | int ret = overflowValue >= 0 ? NO_END : overflowValue; 67 | 68 | // / * * / comments 69 | boolean isComment = (overflowValue == OVERFLOW_COMMENT); 70 | 71 | String quoteChar = null; 72 | if (overflowValue == OVERFLOW_SINGLE_QUOTE) { 73 | quoteChar = "'"; 74 | } else if (overflowValue == OVERFLOW_DOUBLE_QUOTE) { 75 | quoteChar = "\""; 76 | } 77 | 78 | boolean isAlphaDelimiter = StringUtils.isAlpha(delimiter); 79 | 80 | if (line == null || line.length() == 0) { 81 | return ret; 82 | } 83 | 84 | int pos = 0; 85 | int maxpos = line.length() - 1; 86 | 87 | char c1; 88 | char c2 = line.charAt(0); 89 | statement: 90 | do { 91 | if (isComment) { 92 | do { 93 | // keep c2 in line 94 | if (pos < maxpos) { 95 | c2 = line.charAt(pos + 1); 96 | } 97 | 98 | if (startsWith(line, '*', pos) && startsWith(line, '/', pos + 1)) { 99 | ret = NO_END; 100 | isComment = false; 101 | pos++; 102 | 103 | continue statement; 104 | } 105 | } while (pos++ < maxpos); 106 | 107 | // reached EOL 108 | break statement; 109 | } 110 | 111 | // if in quote-mode, search for end quote, respecting escaped characters 112 | if (quoteChar != null) { 113 | String doubleQuote = quoteChar + quoteChar; 114 | do { 115 | // keep c2 in line 116 | if (pos < maxpos) { 117 | c2 = line.charAt(pos + 1); 118 | } 119 | 120 | if (startsWith(line, "\\", pos) || startsWith(line, doubleQuote, pos)) { 121 | // skip next character, but stay in quote-mode 122 | pos++; 123 | } else if (startsWith(line, quoteChar, pos)) { 124 | ret = NO_END; 125 | quoteChar = null; 126 | 127 | continue statement; 128 | } 129 | } while (pos++ < maxpos); 130 | 131 | // reach EOL 132 | break statement; 133 | } 134 | 135 | // use the nextchar from the previous iteration 136 | c1 = c2; 137 | if (pos < maxpos) { 138 | // and set the following char 139 | c2 = line.charAt(pos + 1); 140 | } else { 141 | // or reset to blank if the line has ended 142 | c2 = ' '; 143 | } 144 | 145 | // verify if current char indicates start of new quoted block 146 | if (c1 == '\'' || c1 == '"') { 147 | quoteChar = String.valueOf(c1); 148 | ret = quoteChar.equals("'") ? OVERFLOW_SINGLE_QUOTE : OVERFLOW_DOUBLE_QUOTE; 149 | continue statement; 150 | } 151 | 152 | // parse for a / * start of comment 153 | if (c1 == '/' && c2 == '*') { 154 | isComment = true; 155 | pos++; 156 | ret = OVERFLOW_COMMENT; 157 | continue statement; 158 | } 159 | 160 | if (c1 == '-' && c2 == '-') { 161 | return ret; 162 | } 163 | 164 | if (startsWith(line, delimiter, pos)) { 165 | if (isAlphaDelimiter) { 166 | // check if delimiter is at start or end of line, surrounded 167 | // by non-alpha character 168 | if ((pos == 0 || !isAlpha(line.charAt(pos - 1))) 169 | && (line.length() == pos + delimiter.length() 170 | || !isAlpha(line.charAt(pos + delimiter.length())))) { 171 | return pos + delimiter.length(); 172 | } 173 | } else { 174 | return pos + delimiter.length(); 175 | } 176 | } 177 | 178 | } while (maxpos > pos++); 179 | 180 | return ret; 181 | } 182 | 183 | /** 184 | * Small performance optimized replacement for {@link String#startsWith(String, int)}. 185 | * 186 | * @param toParse the String to parse 187 | * @param delimiter the delimiter to look for 188 | * @param position the initial position to start the scan with 189 | */ 190 | private static boolean startsWith(String toParse, String delimiter, int position) { 191 | if (delimiter.length() == 1) { 192 | return toParse.length() > position && toParse.charAt(position) == delimiter.charAt(0); 193 | } else { 194 | return toParse.startsWith(delimiter, position); 195 | } 196 | } 197 | 198 | /** 199 | * @param toParse the String to parse 200 | * @param delimiter the delimiter to look for 201 | * @param position the initial position to start the scan with 202 | * @return 203 | */ 204 | private static boolean startsWith(String toParse, char delimiter, int position) { 205 | return toParse.length() > position && toParse.charAt(position) == delimiter; 206 | } 207 | 208 | /** 209 | * @param c the char to check 210 | * @return true if the given character is either a lower or an upperchase alphanumerical character 211 | */ 212 | private static boolean isAlpha(char c) { 213 | return Character.isUpperCase(c) || Character.isLowerCase(c); 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 4.0.0 5 | 6 | 7 | org.codehaus.mojo 8 | mojo-parent 9 | 94 10 | 11 | 12 | sql-maven-plugin 13 | 3.1.0-SNAPSHOT 14 | maven-plugin 15 | SQL Maven Plugin 16 | Execute SQL Statements 17 | 2006 18 | 19 | 20 | 21 | Apache License 2 22 | http://www.apache.org/licenses/LICENSE-2.0.txt 23 | repo 24 | 25 | 26 | 27 | 28 | 29 | topping 30 | Brian Topping 31 | topping@codehaus.org 32 | 33 | Java Developer 34 | 35 | +8 36 | 37 | 38 | dtran 39 | Dan Tran 40 | dantran@apache.org 41 | 42 | Java Developer 43 | 44 | 45 | 46 | struberg 47 | Mark Struberg 48 | struberg@yahoo.de 49 | 50 | Java Developer 51 | 52 | +1 53 | 54 | 55 | rfscholte 56 | Robert Scholte 57 | rfscholte@codehaus.org 58 | 59 | Java Developer 60 | 61 | Europe/Amsterdam 62 | 63 | 64 | khmarbaise 65 | Karl-Heinz Marbaise 66 | khmarbaise@apache.org 67 | 68 | Java Developer 69 | 70 | Europe/Berlin 71 | 72 | 73 | Vaibhav 74 | Vaibhav Singh 75 | vbhav.singh@gmail.com 76 | 77 | Java Developer 78 | 79 | America/New_york 80 | 81 | 82 | 83 | 84 | ${mavenVersion} 85 | 86 | 87 | scm:git:https://github.com/mojohaus/sql-maven-plugin.git 88 | scm:git:ssh://git@github.com/mojohaus/sql-maven-plugin.git 89 | HEAD 90 | https://github.com/mojohaus/sql-maven-plugin/ 91 | 92 | 93 | 94 | github 95 | https://github.com/mojohaus/${project.artifactId}/issues 96 | 97 | 98 | 99 | 100 | 10.14.2.0 101 | target/staging/${project.artifactId} 102 | 103 | 104 | 105 | 106 | 107 | org.codehaus.plexus 108 | plexus-utils 109 | 4.0.2 110 | 111 | 112 | 113 | org.apache.groovy 114 | groovy 115 | 5.0.1 116 | 117 | 118 | 119 | 120 | 121 | junit 122 | junit 123 | test 124 | 125 | 126 | org.apache.maven.plugin-tools 127 | maven-plugin-annotations 128 | provided 129 | 130 | 131 | org.apache.maven 132 | maven-plugin-api 133 | ${mavenVersion} 134 | provided 135 | 136 | 137 | org.apache.maven 138 | maven-core 139 | ${mavenVersion} 140 | provided 141 | 142 | 143 | org.sonatype.plexus 144 | plexus-sec-dispatcher 145 | 146 | 147 | 148 | 149 | org.apache.maven 150 | maven-settings 151 | ${mavenVersion} 152 | provided 153 | 154 | 155 | org.apache.maven.shared 156 | maven-script-interpreter 157 | 1.6 158 | 159 | 160 | org.codehaus.plexus 161 | plexus-utils 162 | 163 | 164 | org.codehaus.plexus 165 | plexus-xml 166 | 3.0.1 167 | 168 | 169 | org.codehaus.plexus 170 | plexus-interpolation 171 | 1.28 172 | 173 | 174 | 175 | org.apache.commons 176 | commons-lang3 177 | 3.19.0 178 | 179 | 180 | org.apache.commons 181 | commons-text 182 | 1.14.0 183 | 184 | 185 | org.apache.maven.shared 186 | maven-filtering 187 | 3.4.0 188 | 189 | 190 | org.codehaus.plexus 191 | plexus-sec-dispatcher 192 | 2.0 193 | 194 | 195 | org.apache.maven 196 | maven-compat 197 | ${mavenVersion} 198 | test 199 | 200 | 201 | org.apache.maven.plugin-testing 202 | maven-plugin-testing-harness 203 | 3.3.0 204 | test 205 | 206 | 207 | org.hsqldb 208 | hsqldb 209 | 2.7.4 210 | jdk8 211 | test 212 | 213 | 214 | org.slf4j 215 | slf4j-simple 216 | 1.7.36 217 | test 218 | 219 | 220 | 221 | 222 | 223 | run-its 224 | 225 | 226 | 227 | org.apache.maven.plugins 228 | maven-invoker-plugin 229 | 230 | true 231 | ${project.build.directory}/it 232 | 233 | verify 234 | ${project.build.directory}/local-repo 235 | src/it/settings.xml 236 | 237 | ${project.basedir}/src/it/settings-security.xml 238 | 239 | 240 | clean 241 | sql:execute 242 | 243 | 244 | 245 | 246 | 247 | install 248 | run 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /src/test/java/org/codehaus/mojo/sql/SqlSplitterTest.java: -------------------------------------------------------------------------------- 1 | package org.codehaus.mojo.sql; 2 | 3 | /* 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | 22 | import java.io.BufferedReader; 23 | import java.io.StringReader; 24 | import java.util.logging.Logger; 25 | 26 | import junit.framework.TestCase; 27 | 28 | public class SqlSplitterTest extends TestCase { 29 | 30 | public void testContainsSqlString() throws Exception { 31 | containsNot(""); 32 | containsNot(" "); 33 | containsNot(" \t "); 34 | 35 | contains(";", 1); 36 | contains("SELECT * from myTable;", 22); 37 | 38 | contains("SELECT * from myTable; -- with sl comment", 22); 39 | contains("SELECT * from myTable; /* with part comment */", 22); 40 | 41 | contains("SELECT * from myTable /* with part comment inside*/ ; ", 54); 42 | 43 | contains("SELECT * from myTable /* with ; semicolon*/ ; ", 46); 44 | 45 | contains("INSERT INTO testTable (thevalue) VALUES ('value !'); -- comment at the end", 53); 46 | 47 | // a " inside a ' quoted text 48 | contains("INSERT INTO testTable (thevalue) VALUES ('value \" !');", 55); 49 | 50 | // a ' inside a " quoted text 51 | contains("INSERT INTO testTable (thevalue) VALUES (\"value ' !\");", 55); 52 | 53 | contains("INSERT INTO testTable (thevalue) VALUES (\"value -- \");", 55); 54 | contains("INSERT INTO testTable (thevalue) VALUES ('value -- ');", 55); 55 | 56 | containsNot("SELECT * from myTable where value = ';' AND -- semicolon is quoted!"); 57 | 58 | contains("INSERT INTO testTable (thevalue) VALUES (' text '' other ');", 60); 59 | 60 | // 61 | contains("INSERT INTO testTable (thevalue) VALUES ('value !'); -- comment with ' single quote", 53); 62 | contains("SELECT * from myTable /* comment with ' single quote */ ; ", 58); 63 | } 64 | 65 | /** 66 | * This unit test is meant for checking the performance with a profiler 67 | */ 68 | public void testSplitterPerformance() throws Exception { 69 | long startTime = System.currentTimeMillis(); 70 | for (int i = 0; i < 10000; i++) { 71 | contains( 72 | "INSERT INTO testTable (thevalue1, thevalue2, anothervalue3, justmore, andevenmore) " 73 | + "/*it might also contain lots of other really loooooong and useless comments...*/ " 74 | + "/*it might also contain lots of other really loooooong and useless comments...*/ " 75 | + "/*it might also contain lots of other really loooooong and useless comments...*/ " 76 | + "/*it might also contain lots of other really loooooong and useless comments...*/ " 77 | + "/*it might also contain lots of other really loooooong and useless comments...*/ " 78 | + "/*it might also contain lots of other really loooooong and useless comments...*/ " 79 | + "/*it might also contain lots of other really loooooong and useless comments...*/ " 80 | + "/*it might also contain lots of other really loooooong and useless comments...*/ " 81 | + "/*it might also contain lots of other really loooooong and useless comments...*/ " 82 | + "/*it might also contain lots of other really loooooong and useless comments...*/ " 83 | + "/*it might also contain lots of other really loooooong and useless comments...*/ " 84 | + "/*it might also contain lots of other really loooooong and useless comments...*/ " 85 | + "/*it might also contain lots of other really loooooong and useless comments...*/ " 86 | + "/*it might also contain lots of other really loooooong and useless comments...*/ " 87 | + "/*it might also contain lots of other really loooooong and useless comments...*/ " 88 | + "/*it might also contain lots of other really loooooong and useless comments...*/ " 89 | + "/*it might also contain lots of other really loooooong and useless comments...*/ " 90 | + "/*it might also contain lots of other really loooooong and useless comments...*/ " 91 | + "/*it might also contain lots of other really loooooong and useless comments...*/ " 92 | + "/*it might also contain lots of other really loooooong and useless comments...*/ " 93 | + "/*it might also contain lots of other really loooooong and useless comments...*/ " 94 | + "/*it might also contain lots of other really loooooong and useless comments...*/ " 95 | + "/*it might also contain lots of other really loooooong and useless comments...*/ " 96 | + "/*it might also contain lots of other really loooooong and useless comments...*/ " 97 | + "/*it might also contain lots of other really loooooong and useless comments...*/ " 98 | + "/*it might also contain lots of other really loooooong and useless comments...*/ " 99 | + "/*it might also contain lots of other really loooooong and useless comments...*/ " 100 | + "/*it might also contain lots of other really loooooong and useless comments...*/ " 101 | + "/*it might also contain lots of other really loooooong and useless comments...*/ " 102 | + "/*it might also contain lots of other really loooooong and useless comments...*/ " 103 | + "/*it might also contain lots of other really loooooong and useless comments...*/ " 104 | + "/*it might also contain lots of other really loooooong and useless comments...*/ " 105 | + "/*it might also contain lots of other really loooooong and useless comments...*/ " 106 | + "/*it might also contain lots of other really loooooong and useless comments...*/ " 107 | + "/*it might also contain lots of other really loooooong and useless comments...*/ " 108 | + "/*it might also contain lots of other really loooooong and useless comments...*/ " 109 | + "/*it might also contain lots of other really loooooong and useless comments...*/ " 110 | + "/*it might also contain lots of other really loooooong and useless comments...*/ " 111 | + "/*it might also contain lots of other really loooooong and useless comments...*/ " 112 | + "/*it might also contain lots of other really loooooong and useless comments...*/ " 113 | + "/*it might also contain lots of other really loooooong and useless comments...*/ " 114 | + "/*it might also contain lots of other really loooooong and useless comments...*/ " 115 | + "/*it might also contain lots of other really loooooong and useless comments...*/ " 116 | + "/*it might also contain lots of other really loooooong and useless comments...*/ " 117 | + "/*it might also contain lots of other really loooooong and useless comments...*/ " 118 | + "/*it might also contain lots of other really loooooong and useless comments...*/ " 119 | + "VALUES ('value !', 'else', 'more', 'hopefullyfast');", 120 | 3861); 121 | } 122 | 123 | long duration = System.currentTimeMillis() - startTime; 124 | Logger log = Logger.getLogger(SqlSplitterTest.class.getName()); 125 | log.info("SqlPlitterTest performance took [ms]: " + duration); 126 | } 127 | 128 | public void testMsSQLStrings() throws Exception { 129 | String del = "GO"; 130 | 131 | containsNot("SELECT COUNT(*) FROM Logs", del); 132 | containsNot("SELECT * FROM TPersons", del); 133 | contains("GO", del, 2); 134 | } 135 | 136 | // MSQL-48 137 | public void testSQLContainingRegExp() throws Exception { 138 | String sql = "EXECUTE IMMEDIATE 'PROCEDURE my_sproc(' ||\r\n" 139 | + "' ...' ||\r\n" + "' ...' ||\r\n" 140 | + "' ...REGEXP_INSTR(v_foo, '''^[A-Za-z0-9]{2}[0-9]{3,4}$''') ...' ||\r\n" 141 | + "'...' ||\r\n" 142 | + "'EXCEPTION' ||\r\n" + "'WHEN OTHERS THEN' ||\r\n" 143 | + "' DBMS_OUTPUT.put_line (''Error stack at top level:'');' ||\r\n" 144 | + "' putline (DBMS_UTILITY.format_error_backtrace);' ||\r\n" 145 | + "' bt.show_info (DBMS_UTILITY.format_error_backtrace);' ||\r\n" 146 | + "'END my_sproc;'"; 147 | BufferedReader in = new BufferedReader(new StringReader(sql)); 148 | 149 | // Only checking if this complex statement can be parsed 150 | String line; 151 | int lineNr = 0; 152 | for (; (line = in.readLine()) != null; lineNr++) { 153 | SqlSplitter.containsSqlEnd(line, ";", SqlSplitter.NO_END); 154 | } 155 | assertEquals("Not every line is parsed", 11, lineNr); 156 | } 157 | 158 | public void testOverflows() { 159 | assertEquals( 160 | SqlSplitter.OVERFLOW_SINGLE_QUOTE, 161 | SqlSplitter.containsSqlEnd("test 'with an open singlequote statics;", ";", SqlSplitter.NO_END)); 162 | assertEquals( 163 | SqlSplitter.OVERFLOW_SINGLE_QUOTE, 164 | SqlSplitter.containsSqlEnd("test 'with an open singlequote statics;lalala", ";", SqlSplitter.NO_END)); 165 | 166 | assertEquals( 167 | SqlSplitter.OVERFLOW_DOUBLE_QUOTE, 168 | SqlSplitter.containsSqlEnd("test \"with an open doublequote statics;", ";", SqlSplitter.NO_END)); 169 | assertEquals( 170 | SqlSplitter.OVERFLOW_DOUBLE_QUOTE, 171 | SqlSplitter.containsSqlEnd("test \"with an open doublequote statics;lalala", ";", SqlSplitter.NO_END)); 172 | 173 | assertEquals( 174 | 39, 175 | SqlSplitter.containsSqlEnd( 176 | "test \"with an open doublequote statics;", ";", SqlSplitter.OVERFLOW_DOUBLE_QUOTE)); 177 | 178 | assertEquals( 179 | SqlSplitter.OVERFLOW_SINGLE_QUOTE, 180 | SqlSplitter.containsSqlEnd( 181 | "test \"with an open doublequote statics;", ";", SqlSplitter.OVERFLOW_SINGLE_QUOTE)); 182 | assertEquals( 183 | 40, 184 | SqlSplitter.containsSqlEnd( 185 | "test \"with an open doublequote statics';", ";", SqlSplitter.OVERFLOW_SINGLE_QUOTE)); 186 | 187 | assertEquals( 188 | SqlSplitter.OVERFLOW_DOUBLE_QUOTE, 189 | SqlSplitter.containsSqlEnd( 190 | "test 'with an open singlequote statics;", ";", SqlSplitter.OVERFLOW_DOUBLE_QUOTE)); 191 | assertEquals( 192 | 40, 193 | SqlSplitter.containsSqlEnd( 194 | "test 'with an open singlequote statics\";", ";", SqlSplitter.OVERFLOW_DOUBLE_QUOTE)); 195 | 196 | assertEquals( 197 | SqlSplitter.OVERFLOW_COMMENT, SqlSplitter.containsSqlEnd("test /* comment;", ";", SqlSplitter.NO_END)); 198 | assertEquals( 199 | SqlSplitter.OVERFLOW_COMMENT, 200 | SqlSplitter.containsSqlEnd("comment; continued", ";", SqlSplitter.OVERFLOW_COMMENT)); 201 | assertEquals(16, SqlSplitter.containsSqlEnd("test */ comment;", ";", SqlSplitter.OVERFLOW_COMMENT)); 202 | 203 | // test value divided over 2 lines, second line hits a comment first 204 | assertEquals( 205 | SqlSplitter.OVERFLOW_SINGLE_QUOTE, 206 | SqlSplitter.containsSqlEnd("INSERT INTO topics VALUES( 'did you know: ", ";", SqlSplitter.NO_END)); 207 | assertEquals( 208 | 33, 209 | SqlSplitter.containsSqlEnd( 210 | "javadoc always starts with /**');", ";", SqlSplitter.OVERFLOW_SINGLE_QUOTE)); 211 | 212 | // bare minimums 213 | assertEquals(SqlSplitter.NO_END, SqlSplitter.containsSqlEnd("'", ";", SqlSplitter.OVERFLOW_SINGLE_QUOTE)); 214 | assertEquals(SqlSplitter.NO_END, SqlSplitter.containsSqlEnd("\"", ";", SqlSplitter.OVERFLOW_DOUBLE_QUOTE)); 215 | assertEquals(SqlSplitter.NO_END, SqlSplitter.containsSqlEnd("*/", ";", SqlSplitter.OVERFLOW_COMMENT)); 216 | 217 | assertEquals(SqlSplitter.OVERFLOW_SINGLE_QUOTE, SqlSplitter.containsSqlEnd("'", ";", SqlSplitter.NO_END)); 218 | assertEquals(SqlSplitter.OVERFLOW_DOUBLE_QUOTE, SqlSplitter.containsSqlEnd("\"", ";", SqlSplitter.NO_END)); 219 | assertEquals(SqlSplitter.OVERFLOW_COMMENT, SqlSplitter.containsSqlEnd("/*", ";", SqlSplitter.NO_END)); 220 | 221 | assertEquals( 222 | SqlSplitter.OVERFLOW_SINGLE_QUOTE, 223 | SqlSplitter.containsSqlEnd("", ";", SqlSplitter.OVERFLOW_SINGLE_QUOTE)); 224 | assertEquals( 225 | SqlSplitter.OVERFLOW_SINGLE_QUOTE, 226 | SqlSplitter.containsSqlEnd("\"", ";", SqlSplitter.OVERFLOW_SINGLE_QUOTE)); 227 | assertEquals( 228 | SqlSplitter.OVERFLOW_SINGLE_QUOTE, 229 | SqlSplitter.containsSqlEnd("/*", ";", SqlSplitter.OVERFLOW_SINGLE_QUOTE)); 230 | assertEquals( 231 | SqlSplitter.OVERFLOW_SINGLE_QUOTE, 232 | SqlSplitter.containsSqlEnd("*/", ";", SqlSplitter.OVERFLOW_SINGLE_QUOTE)); 233 | assertEquals( 234 | SqlSplitter.OVERFLOW_SINGLE_QUOTE, 235 | SqlSplitter.containsSqlEnd("''", ";", SqlSplitter.OVERFLOW_SINGLE_QUOTE)); 236 | assertEquals( 237 | SqlSplitter.OVERFLOW_SINGLE_QUOTE, 238 | SqlSplitter.containsSqlEnd("\"\"", ";", SqlSplitter.OVERFLOW_SINGLE_QUOTE)); 239 | 240 | assertEquals( 241 | SqlSplitter.OVERFLOW_DOUBLE_QUOTE, 242 | SqlSplitter.containsSqlEnd("", ";", SqlSplitter.OVERFLOW_DOUBLE_QUOTE)); 243 | assertEquals( 244 | SqlSplitter.OVERFLOW_DOUBLE_QUOTE, 245 | SqlSplitter.containsSqlEnd("'", ";", SqlSplitter.OVERFLOW_DOUBLE_QUOTE)); 246 | assertEquals( 247 | SqlSplitter.OVERFLOW_DOUBLE_QUOTE, 248 | SqlSplitter.containsSqlEnd("/*", ";", SqlSplitter.OVERFLOW_DOUBLE_QUOTE)); 249 | assertEquals( 250 | SqlSplitter.OVERFLOW_DOUBLE_QUOTE, 251 | SqlSplitter.containsSqlEnd("*/", ";", SqlSplitter.OVERFLOW_DOUBLE_QUOTE)); 252 | assertEquals( 253 | SqlSplitter.OVERFLOW_DOUBLE_QUOTE, 254 | SqlSplitter.containsSqlEnd("''", ";", SqlSplitter.OVERFLOW_DOUBLE_QUOTE)); 255 | assertEquals( 256 | SqlSplitter.OVERFLOW_DOUBLE_QUOTE, 257 | SqlSplitter.containsSqlEnd("\"\"", ";", SqlSplitter.OVERFLOW_DOUBLE_QUOTE)); 258 | 259 | assertEquals(SqlSplitter.OVERFLOW_COMMENT, SqlSplitter.containsSqlEnd("", ";", SqlSplitter.OVERFLOW_COMMENT)); 260 | assertEquals(SqlSplitter.OVERFLOW_COMMENT, SqlSplitter.containsSqlEnd("'", ";", SqlSplitter.OVERFLOW_COMMENT)); 261 | assertEquals(SqlSplitter.OVERFLOW_COMMENT, SqlSplitter.containsSqlEnd("\"", ";", SqlSplitter.OVERFLOW_COMMENT)); 262 | assertEquals(SqlSplitter.OVERFLOW_COMMENT, SqlSplitter.containsSqlEnd("/*", ";", SqlSplitter.OVERFLOW_COMMENT)); 263 | assertEquals(SqlSplitter.OVERFLOW_COMMENT, SqlSplitter.containsSqlEnd("''", ";", SqlSplitter.OVERFLOW_COMMENT)); 264 | assertEquals( 265 | SqlSplitter.OVERFLOW_COMMENT, SqlSplitter.containsSqlEnd("\"\"", ";", SqlSplitter.OVERFLOW_COMMENT)); 266 | 267 | // escaped escape character 268 | assertEquals(SqlSplitter.NO_END, SqlSplitter.containsSqlEnd("\\\\'", ";", SqlSplitter.OVERFLOW_SINGLE_QUOTE)); 269 | assertEquals( 270 | SqlSplitter.OVERFLOW_SINGLE_QUOTE, 271 | SqlSplitter.containsSqlEnd("\\'", ";", SqlSplitter.OVERFLOW_SINGLE_QUOTE)); 272 | } 273 | 274 | public void testAlphaDelimiter() throws Exception { 275 | assertEquals(2, SqlSplitter.containsSqlEnd("go", "go", SqlSplitter.NO_END)); 276 | assertEquals(2, SqlSplitter.containsSqlEnd("Go", "Go", SqlSplitter.NO_END)); 277 | assertEquals(5, SqlSplitter.containsSqlEnd(" GO", "GO", SqlSplitter.NO_END)); 278 | assertEquals(2, SqlSplitter.containsSqlEnd("GO ", "GO", SqlSplitter.NO_END)); 279 | } 280 | 281 | /** 282 | * Test a problem with single quotes split over multiple lines 283 | * 284 | * @throws Exception 285 | */ 286 | public void testSqlSingleQuotesInDifferentLines() throws Exception { 287 | // @formatter:off 288 | String sql = "BEGIN\n" 289 | + "requete='INSERT INTO rid_oid(rid,oids)\n" 290 | + " VALUE('||quote_literal(rid)||',' \n" 291 | + " ||quote_literal(Oid)||')';\n" 292 | + "EXECUTE requete;"; 293 | // @formatter:on 294 | 295 | BufferedReader in = new BufferedReader(new StringReader(sql)); 296 | 297 | // Only checking if this complex statement can be parsed 298 | String line; 299 | 300 | line = in.readLine(); 301 | assertEquals(SqlSplitter.NO_END, SqlSplitter.containsSqlEnd(line, ";", SqlSplitter.NO_END)); 302 | 303 | line = in.readLine(); 304 | assertEquals(SqlSplitter.OVERFLOW_SINGLE_QUOTE, SqlSplitter.containsSqlEnd(line, ";", SqlSplitter.NO_END)); 305 | 306 | line = in.readLine(); 307 | assertEquals(SqlSplitter.NO_END, SqlSplitter.containsSqlEnd(line, ";", SqlSplitter.OVERFLOW_SINGLE_QUOTE)); 308 | 309 | line = in.readLine(); 310 | assertEquals(35, SqlSplitter.containsSqlEnd(line, ";", SqlSplitter.NO_END)); 311 | 312 | line = in.readLine(); 313 | assertEquals(16, SqlSplitter.containsSqlEnd(line, ";", SqlSplitter.NO_END)); 314 | } 315 | 316 | /** 317 | * Test if separators inside multi-line comments get ignored. See MSQL-67 318 | * 319 | * @throws Exception 320 | */ 321 | public void testSemicolonInComment() throws Exception { 322 | // @formatter:off 323 | String sql = 324 | "/* this is a commented-out statment:\n" + " SELECT * FROM TABLE;\n" + "and here the comment ends */ "; 325 | // @formatter:on 326 | 327 | BufferedReader in = new BufferedReader(new StringReader(sql)); 328 | 329 | // Only checking if this complex statement can be parsed 330 | String line; 331 | 332 | line = in.readLine(); 333 | assertEquals(SqlSplitter.OVERFLOW_COMMENT, SqlSplitter.containsSqlEnd(line, ";", SqlSplitter.NO_END)); 334 | 335 | line = in.readLine(); 336 | assertEquals(SqlSplitter.OVERFLOW_COMMENT, SqlSplitter.containsSqlEnd(line, ";", SqlSplitter.OVERFLOW_COMMENT)); 337 | 338 | line = in.readLine(); 339 | assertEquals(SqlSplitter.NO_END, SqlSplitter.containsSqlEnd(line, ";", SqlSplitter.OVERFLOW_COMMENT)); 340 | } 341 | 342 | public void testSlashDelimiterWithComment() throws Exception { 343 | 344 | String sql = "begin\n/* this is a comment */\n SELECT * FROM TABLE;\nend;\n/\n"; 345 | 346 | BufferedReader in = new BufferedReader(new StringReader(sql)); 347 | 348 | // Only checking if this complex statement can be parsed 349 | String line; 350 | 351 | line = in.readLine(); 352 | assertEquals(SqlSplitter.NO_END, SqlSplitter.containsSqlEnd(line, "/", SqlSplitter.NO_END)); 353 | 354 | line = in.readLine(); 355 | assertEquals(SqlSplitter.NO_END, SqlSplitter.containsSqlEnd(line, "/", SqlSplitter.NO_END)); 356 | 357 | line = in.readLine(); 358 | assertEquals(SqlSplitter.NO_END, SqlSplitter.containsSqlEnd(line, "/", SqlSplitter.NO_END)); 359 | 360 | line = in.readLine(); 361 | assertEquals(SqlSplitter.NO_END, SqlSplitter.containsSqlEnd(line, "/", SqlSplitter.NO_END)); 362 | 363 | line = in.readLine(); 364 | assertEquals(1, SqlSplitter.containsSqlEnd(line, "/", SqlSplitter.NO_END)); 365 | } 366 | 367 | private void contains(String sql, int expectedIndex) throws Exception { 368 | contains(sql, ";", expectedIndex); 369 | } 370 | 371 | private void containsNot(String sql) throws Exception { 372 | containsNot(sql, ";"); 373 | } 374 | 375 | private void contains(String sql, String delimiter, int expectedIndex) throws Exception { 376 | assertEquals(sql, expectedIndex, SqlSplitter.containsSqlEnd(sql, delimiter, SqlSplitter.NO_END)); 377 | } 378 | 379 | private void containsNot(String sql, String delimiter) throws Exception { 380 | assertTrue(sql, SqlSplitter.containsSqlEnd(sql, delimiter, SqlSplitter.NO_END) == SqlSplitter.NO_END); 381 | } 382 | } 383 | -------------------------------------------------------------------------------- /src/test/java/org/codehaus/mojo/sql/SqlExecMojoTest.java: -------------------------------------------------------------------------------- 1 | package org.codehaus.mojo.sql; 2 | 3 | /* 4 | * Copyright 2006 The Codehaus 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 7 | * in compliance with the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software distributed under the License 12 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 13 | * or implied. See the License for the specific language governing permissions and limitations under 14 | * the License. 15 | */ 16 | 17 | import java.io.File; 18 | import java.nio.charset.StandardCharsets; 19 | import java.nio.file.Files; 20 | import java.sql.Connection; 21 | import java.sql.Statement; 22 | import java.util.Arrays; 23 | import java.util.List; 24 | import java.util.Properties; 25 | import java.util.UUID; 26 | 27 | import org.apache.maven.plugin.MojoExecutionException; 28 | import org.apache.maven.plugin.testing.AbstractMojoTestCase; 29 | import org.apache.maven.plugin.testing.stubs.MavenProjectStub; 30 | import org.apache.maven.project.MavenProject; 31 | import org.apache.maven.settings.Server; 32 | import org.apache.maven.settings.Settings; 33 | import org.apache.maven.shared.filtering.MavenFileFilter; 34 | import org.codehaus.plexus.component.repository.exception.ComponentLookupException; 35 | import org.sonatype.plexus.components.sec.dispatcher.SecDispatcher; 36 | 37 | /** 38 | * Unit test for simple SqlExecMojo. 39 | */ 40 | public class SqlExecMojoTest extends AbstractMojoTestCase { 41 | 42 | // jdbc:hsqldb:mem:egdb;sql.enforce_size=false 43 | // Group 1 ([^;]+) : "jdbc:hsqldb:mem:egdb" 44 | // Group 2 (;.*)? : ";sql.enforce_size=false" 45 | private static final String URL_REGEXP = "([^;]+)(;.*)?"; 46 | 47 | private Properties p; 48 | 49 | public void setUp() throws Exception { 50 | super.setUp(); 51 | p = new Properties(); 52 | p.load(getClass().getResourceAsStream("/test.properties")); 53 | } 54 | 55 | /** 56 | * No error when there is no input 57 | */ 58 | public void testNoCommandMojo() throws MojoExecutionException { 59 | SqlExecMojo mojo = createMojo(); 60 | mojo.execute(); 61 | 62 | assertEquals(0, mojo.getSuccessfulStatements()); 63 | } 64 | 65 | public void testCreateCommandMojo() throws MojoExecutionException { 66 | SqlExecMojo mojo = createMojo(); 67 | String command = 68 | "create table CREATE_COMMAND ( PERSON_ID integer, FIRSTNAME varchar(50), LASTNAME varchar(50))"; 69 | mojo.addText(command); 70 | mojo.execute(); 71 | 72 | assertEquals(1, mojo.getSuccessfulStatements()); 73 | } 74 | 75 | public void testDropCommandMojo() throws MojoExecutionException { 76 | SqlExecMojo mojo = createMojo(); 77 | mojo.setSqlCommand("create table DROP_TEST (id integer)"); 78 | mojo.execute(); 79 | 80 | mojo.clear(); 81 | mojo.addText("drop table DROP_TEST"); 82 | mojo.execute(); 83 | 84 | assertEquals(1, mojo.getSuccessfulStatements()); 85 | } 86 | 87 | public void testFileSetMojo() throws MojoExecutionException { 88 | 89 | Fileset ds = new Fileset(); 90 | ds.setBasedir("src/test"); 91 | ds.setIncludes(new String[] {"**/create*.sql"}); 92 | ds.scan(); 93 | assert (ds.getIncludedFiles().length == 1); 94 | 95 | SqlExecMojo mojo = createMojo(); 96 | mojo.setFileset(ds); 97 | 98 | mojo.execute(); 99 | 100 | assertEquals(3, mojo.getSuccessfulStatements()); 101 | } 102 | 103 | public void testFileArrayMojo() throws MojoExecutionException { 104 | File[] srcFiles = new File[2]; 105 | srcFiles[0] = new File("src/test/data/create-test-tables.sql"); 106 | srcFiles[1] = new File("src/test/data/drop-test-tables.sql"); 107 | 108 | SqlExecMojo mojo = createMojo(); 109 | mojo.setSrcFiles(srcFiles); 110 | mojo.execute(); 111 | 112 | assertEquals(6, mojo.getSuccessfulStatements()); 113 | } 114 | 115 | /** 116 | * Ensure srcFiles always execute first 117 | */ 118 | public void testAllMojo() throws MojoExecutionException { 119 | SqlExecMojo mojo = createMojo(); 120 | String command = "create table PERSON2 ( PERSON_ID integer, FIRSTNAME varchar(50), LASTNAME varchar(50))"; 121 | mojo.addText(command); 122 | 123 | File[] srcFiles = new File[1]; 124 | srcFiles[0] = new File("src/test/data/create-test-tables.sql"); 125 | mojo.setSrcFiles(srcFiles); 126 | 127 | Fileset ds = new Fileset(); 128 | ds.setBasedir("src/test"); 129 | ds.setIncludes(new String[] {"**/drop*.sql"}); 130 | ds.scan(); 131 | mojo.setFileset(ds); 132 | mojo.execute(); 133 | 134 | assertEquals(7, mojo.getSuccessfulStatements()); 135 | } 136 | 137 | public void testOrderFile() throws MojoExecutionException { 138 | Fileset ds = new Fileset(); 139 | ds.setBasedir("src/test"); 140 | ds.setIncludes(new String[] {"**/drop*.sql", "**/create*.sql"}); 141 | ds.scan(); 142 | 143 | SqlExecMojo mojo = createMojo(); 144 | mojo.setFileset(ds); 145 | mojo.setOrderFile(SqlExecMojo.FILE_SORTING_ASC); 146 | mojo.execute(); 147 | 148 | assertEquals(6, mojo.getSuccessfulStatements()); 149 | 150 | try { 151 | mojo.setOrderFile(SqlExecMojo.FILE_SORTING_DSC); 152 | mojo.execute(); 153 | fail("Execution is not aborted on error."); 154 | } catch (MojoExecutionException e) { 155 | } 156 | } 157 | 158 | public void testOnErrorContinueMojo() throws MojoExecutionException { 159 | SqlExecMojo mojo = createMojo(); 160 | String command = "create table BOGUS"; // bad syntax 161 | mojo.addText(command); 162 | mojo.setOnError("continue"); 163 | mojo.execute(); 164 | assertEquals(0, mojo.getSuccessfulStatements()); 165 | } 166 | 167 | public void testOnErrorAbortMojo() throws MojoExecutionException { 168 | SqlExecMojo mojo = createMojo(); 169 | String command = "create table BOGUS"; // bad syntax 170 | mojo.addText(command); 171 | 172 | try { 173 | mojo.execute(); 174 | fail("Execution is not aborted on error."); 175 | 176 | } catch (MojoExecutionException e) { 177 | 178 | } 179 | 180 | assertEquals(0, mojo.getSuccessfulStatements()); 181 | } 182 | 183 | public void testOnErrorAbortAfterMojo() throws MojoExecutionException { 184 | String commands = "create table BOGUS"; // bad syntax 185 | 186 | SqlExecMojo mojo = createMojo(); 187 | mojo.addText(commands); 188 | 189 | File[] srcFiles = new File[1]; 190 | srcFiles[0] = new File("src/test/data/invalid-syntax.sql"); 191 | 192 | assertTrue(srcFiles[0].exists()); 193 | 194 | mojo.setSrcFiles(srcFiles); 195 | mojo.setOnError("abortAfter"); 196 | 197 | try { 198 | mojo.execute(); 199 | fail("Execution is not aborted on error."); 200 | 201 | } catch (MojoExecutionException e) { 202 | // expected 203 | } 204 | 205 | assertEquals(0, mojo.getSuccessfulStatements()); 206 | assertEquals(2, mojo.getTotalStatements()); 207 | } 208 | 209 | public void testDefaultUsernamePassword() throws MojoExecutionException { 210 | 211 | Settings settings = new Settings(); 212 | Server server = new Server(); 213 | settings.addServer(server); 214 | 215 | SqlExecMojo mojo = createMojo(";user=;password="); 216 | mojo.setSettings(settings); 217 | 218 | // force a lookup of username 219 | mojo.setUsername(null); 220 | mojo.setPassword(null); 221 | 222 | mojo.execute(); 223 | 224 | assertEquals("", mojo.getUsername()); 225 | assertEquals("", mojo.getPassword()); 226 | } 227 | 228 | public void testUsernamePasswordLookup() throws MojoExecutionException { 229 | 230 | Settings settings = new Settings(); 231 | Server server = new Server(); 232 | server.setId("somekey"); 233 | server.setUsername("username"); 234 | server.setPassword("password"); 235 | settings.addServer(server); 236 | 237 | SqlExecMojo mojo = createMojo(";user=username;password=password"); 238 | mojo.setSettings(settings); 239 | 240 | // force a lookup of username 241 | mojo.setSettingsKey("somekey"); 242 | mojo.setUsername(null); 243 | mojo.setPassword(null); 244 | 245 | mojo.execute(); 246 | 247 | assertEquals("username", mojo.getUsername()); 248 | assertEquals("password", mojo.getPassword()); 249 | } 250 | 251 | public void testBadDriver() { 252 | SqlExecMojo mojo = createMojo(); 253 | mojo.setDriver("bad-driver"); 254 | try { 255 | mojo.execute(); 256 | 257 | fail("Bad driver is not detected"); 258 | } catch (MojoExecutionException e) { 259 | 260 | } 261 | } 262 | 263 | public void testBadUrl() { 264 | SqlExecMojo mojo = createMojo(); 265 | mojo.setUrl("bad-url"); 266 | try { 267 | mojo.execute(); 268 | 269 | fail("Bad URL is not detected"); 270 | } catch (MojoExecutionException e) { 271 | 272 | } 273 | } 274 | 275 | public void testBadFile() { 276 | SqlExecMojo mojo = createMojo(); 277 | File[] srcFiles = new File[1]; 278 | srcFiles[0] = new File("a-every-bogus-file-that-does-not-exist"); 279 | 280 | mojo.setSrcFiles(srcFiles); 281 | try { 282 | mojo.execute(); 283 | 284 | fail("Bad files is not detected"); 285 | } catch (MojoExecutionException e) { 286 | 287 | } 288 | } 289 | 290 | public void testOnError() { 291 | SqlExecMojo mojo = createMojo(); 292 | mojo.setOnError("AbOrT"); 293 | assertEquals(SqlExecMojo.ON_ERROR_ABORT, mojo.getOnError()); 294 | mojo.setOnError("cOnTiNuE"); 295 | assertEquals(SqlExecMojo.ON_ERROR_CONTINUE, mojo.getOnError()); 296 | try { 297 | mojo.setOnError("bad"); 298 | fail(IllegalArgumentException.class.getName() + " was not thrown."); 299 | } catch (IllegalArgumentException e) { 300 | // expected 301 | } 302 | try { 303 | mojo.setOnError(null); 304 | fail(IllegalArgumentException.class.getName() + " was not thrown."); 305 | } catch (IllegalArgumentException e) { 306 | // expected 307 | } 308 | } 309 | 310 | public void testSkip() throws MojoExecutionException { 311 | String command = "create table PERSON ( PERSON_ID integer, FIRSTNAME varchar(50), LASTNAME varchar(50))"; 312 | SqlExecMojo mojo = createMojo(); 313 | mojo.addText(command); 314 | mojo.setSkip(true); 315 | mojo.execute(); 316 | 317 | // no command was executed due to skip is on 318 | assertEquals(0, mojo.getSuccessfulStatements()); 319 | } 320 | 321 | public void testDriverProperties() throws MojoExecutionException { 322 | SqlExecMojo mojo = createMojo(); 323 | Properties driverProperties = mojo.getDriverProperties(); 324 | assertEquals(2, driverProperties.size()); 325 | assertEquals("value1", driverProperties.get("key1")); 326 | assertEquals("value2", driverProperties.get("key2")); 327 | 328 | mojo.setDriverProperties("key1=value1,key2"); 329 | try { 330 | driverProperties = mojo.getDriverProperties(); 331 | } catch (MojoExecutionException e) { 332 | } 333 | } 334 | 335 | public void testBlockMode() throws MojoExecutionException { 336 | String command = "create table BLOCKTABLE ( PERSON_ID integer, FIRSTNAME varchar(50), LASTNAME varchar(50))"; 337 | 338 | SqlExecMojo mojo = createMojo(); 339 | mojo.addText(command); 340 | // TODO: Check if this is equal mojo.setEnableBlockMode( true ); 341 | // to the following: 342 | mojo.setDelimiter(DelimiterType.ROW); 343 | mojo.execute(); 344 | assertEquals(1, mojo.getSuccessfulStatements()); 345 | 346 | mojo.setSqlCommand(""); 347 | mojo.getTransactions().clear(); 348 | command = "drop table BLOCKTABLE"; 349 | mojo.addText(command); 350 | mojo.execute(); 351 | assertEquals(1, mojo.getSuccessfulStatements()); 352 | } 353 | 354 | public void testKeepFormat() throws MojoExecutionException { 355 | // Normally a line starting in -- would be ignored, but with keepformat mode 356 | // on it will not. 357 | String command = "--create table PERSON ( PERSON_ID integer, FIRSTNAME varchar(50), LASTNAME varchar(50))"; 358 | 359 | SqlExecMojo mojo = createMojo(); 360 | mojo.addText(command); 361 | mojo.setKeepFormat(true); 362 | 363 | try { 364 | mojo.execute(); 365 | fail("-- at the start of the SQL command is ignored."); 366 | } catch (MojoExecutionException e) { 367 | } 368 | 369 | assertEquals(0, mojo.getSuccessfulStatements()); 370 | } 371 | 372 | public void testBadDelimiter() throws Exception { 373 | String command = "create table SEPARATOR ( PERSON_ID integer, FIRSTNAME varchar(50), LASTNAME varchar(50)):" 374 | + "create table SEPARATOR2 ( PERSON_ID integer, FIRSTNAME varchar(50), LASTNAME varchar(50))"; 375 | 376 | SqlExecMojo mojo = createMojo(); 377 | mojo.addText(command); 378 | mojo.setDelimiter(":"); 379 | 380 | try { 381 | mojo.execute(); 382 | fail("Expected parser error."); 383 | } catch (MojoExecutionException e) { 384 | } 385 | } 386 | 387 | public void testGoodDelimiter() throws Exception { 388 | String command = "create table SEPARATOR ( PERSON_ID integer, FIRSTNAME varchar(50), LASTNAME varchar(50))\n:\n" 389 | + "create table SEPARATOR2 ( PERSON_ID integer, FIRSTNAME varchar(50), LASTNAME varchar(50))"; 390 | 391 | SqlExecMojo mojo = createMojo(); 392 | mojo.addText(command); 393 | mojo.setDelimiter(":"); 394 | 395 | mojo.execute(); 396 | 397 | assertEquals(2, mojo.getSuccessfulStatements()); 398 | } 399 | 400 | public void testBadDelimiterType() throws Exception { 401 | String command = 402 | "create table BADDELIMTYPE ( PERSON_ID integer, FIRSTNAME varchar(50), LASTNAME varchar(50))" + "\n:" 403 | + "create table BADDELIMTYPE2 ( PERSON_ID integer, FIRSTNAME varchar(50), LASTNAME varchar(50))"; 404 | 405 | SqlExecMojo mojo = createMojo(); 406 | mojo.addText(command); 407 | mojo.setDelimiter(":"); 408 | mojo.setDelimiterType(DelimiterType.ROW); 409 | 410 | try { 411 | mojo.execute(); 412 | fail("Expected parser error."); 413 | } catch (MojoExecutionException e) { 414 | } 415 | } 416 | 417 | public void testGoodDelimiterType() throws Exception { 418 | String command = "create table GOODDELIMTYPE ( PERSON_ID integer, FIRSTNAME varchar(50), LASTNAME varchar(50))" 419 | + "\n: \n" 420 | + "create table GOODDELIMTYPE2 ( PERSON_ID integer, FIRSTNAME varchar(50), LASTNAME varchar(50))"; 421 | 422 | SqlExecMojo mojo = createMojo(); 423 | mojo.addText(command); 424 | mojo.setDelimiter(":"); 425 | mojo.setDelimiterType(DelimiterType.NORMAL); 426 | 427 | mojo.execute(); 428 | assertEquals(2, mojo.getSuccessfulStatements()); 429 | } 430 | 431 | public void testOutputFile() throws Exception { 432 | String basedir = System.getProperty("basedir", "."); 433 | File outputFile = new File(basedir, "target/sql.out"); 434 | outputFile.delete(); 435 | 436 | SqlExecMojo mojo = createMojo(); 437 | mojo.setOutputFile(outputFile); 438 | mojo.setPrintResultSet(true); 439 | 440 | String command = 441 | "create table GOODDELIMTYPE3 ( PERSON_ID integer, FIRSTNAME varchar(50), LASTNAME varchar(50));"; 442 | mojo.addText(command); 443 | mojo.execute(); 444 | 445 | List list = Files.readAllLines(outputFile.toPath(), StandardCharsets.UTF_8); 446 | assertEquals(1, list.size()); 447 | assertEquals("0 rows affected", list.get(0)); 448 | 449 | mojo.clear(); 450 | mojo.setSqlCommand("insert into GOODDELIMTYPE3 (person_id) values (1)"); 451 | mojo.execute(); 452 | 453 | list = Files.readAllLines(outputFile.toPath(), StandardCharsets.UTF_8); 454 | assertEquals(1, list.size()); 455 | assertEquals("1 rows affected", list.get(0)); 456 | 457 | mojo.clear(); 458 | mojo.setSqlCommand("select * from GOODDELIMTYPE3"); 459 | mojo.execute(); 460 | 461 | list = Files.readAllLines(outputFile.toPath(), StandardCharsets.UTF_8); 462 | assertEquals(4, list.size()); 463 | assertEquals("PERSON_ID,FIRSTNAME,LASTNAME", list.get(0)); 464 | assertEquals("1,null,null", list.get(1)); 465 | assertEquals("", list.get(2)); 466 | assertEquals("0 rows affected", list.get(3)); 467 | } 468 | 469 | // MSQL-44 470 | public void testAnonymousBlock() throws MojoExecutionException { 471 | String command = "--/ Anonymous SQL Block\n" 472 | + "create table ANONBLOCKTABLE ( PERSON_ID integer, FIRSTNAME varchar(50), LASTNAME varchar(50))\n" 473 | + "/\n" 474 | + "drop table ANONBLOCKTABLE"; 475 | 476 | SqlExecMojo mojo = createMojo(); 477 | mojo.setDelimiter("/"); 478 | mojo.addText(command); 479 | mojo.execute(); 480 | assertEquals(2, mojo.getSuccessfulStatements()); 481 | } 482 | 483 | public void testSkipMissingFiles() throws MojoExecutionException { 484 | SqlExecMojo mojo = createMojo(); 485 | mojo.setSkipMissingFiles(true); 486 | mojo.setSrcFiles(new File[] { 487 | new File("src/test/data/create-test-tables.sql"), 488 | new File("non/existing/file/path.sql"), 489 | new File("src/test/data/drop-test-tables.sql") 490 | }); 491 | mojo.execute(); 492 | assertEquals(6, mojo.getSuccessfulStatements()); 493 | } 494 | 495 | public void testValidationSql() { 496 | SqlExecMojo mojo = createMojo(); 497 | mojo.setConnectionValidationSqls(Arrays.asList("select 1 from nowhere")); 498 | try { 499 | mojo.execute(); 500 | 501 | fail("Invalid connection is not detected"); 502 | } catch (MojoExecutionException e) { 503 | 504 | } 505 | 506 | assertTrue(mojo.isConnectionClosed()); 507 | } 508 | 509 | public void testConnectionRetryCountOnValidationError() { 510 | SqlExecMojo mojo = createMojo(); 511 | mojo.setConnectionValidationSqls(Arrays.asList("select 1 from nowhere")); 512 | mojo.setConnectionRetryCount(2); 513 | try { 514 | mojo.execute(); 515 | 516 | fail("Invalid connection is not detected"); 517 | } catch (MojoExecutionException e) { 518 | 519 | } 520 | 521 | assertTrue(mojo.getConnectionRetryAttempts() >= 2); 522 | assertTrue(mojo.isConnectionClosed()); 523 | } 524 | 525 | public void testConnectionRetryCountOnConnectionError() { 526 | SqlExecMojo mojo = createMojo(); 527 | mojo.setUrl("bad-url"); 528 | mojo.setConnectionRetryCount(2); 529 | try { 530 | mojo.execute(); 531 | 532 | fail("Invalid connection is not detected"); 533 | } catch (MojoExecutionException e) { 534 | } 535 | 536 | assertTrue(mojo.getConnectionRetryAttempts() >= 2); 537 | assertTrue(mojo.isConnectionClosed()); 538 | } 539 | 540 | public void testConnectionRetryIntervalC2I1() { 541 | SqlExecMojo mojo = createMojo(); 542 | mojo.setUrl("no-db-here"); 543 | mojo.setConnectionRetryCount(2); 544 | mojo.setConnectionRetryInterval(1); 545 | 546 | long start = System.currentTimeMillis(); 547 | 548 | try { 549 | mojo.execute(); 550 | fail("Invalid connection is not detected"); 551 | } catch (MojoExecutionException e) { 552 | long end = System.currentTimeMillis(); 553 | assertTrue((end - start) >= 2000); 554 | } 555 | } 556 | 557 | public void testConnectionRetryIntervalC1I2() { 558 | SqlExecMojo mojo = createMojo(); 559 | mojo.setUrl("no-db-here"); 560 | mojo.setConnectionRetryCount(1); 561 | mojo.setConnectionRetryInterval(2); 562 | 563 | long start = System.currentTimeMillis(); 564 | 565 | try { 566 | mojo.execute(); 567 | fail("Invalid connection is not detected"); 568 | } catch (MojoExecutionException e) { 569 | long end = System.currentTimeMillis(); 570 | assertTrue((end - start) >= 2000); 571 | } 572 | } 573 | 574 | public void testConnectionRetryOnConnectionError() { 575 | SqlExecMojo mojo = createMojo(); 576 | final String url = mojo.getUrl(); 577 | mojo.setUrl("bad-url"); 578 | mojo.setConnectionRetryCount(2); 579 | mojo.setConnectionRetryInterval(1); 580 | 581 | new Thread(new Runnable() { 582 | @Override 583 | public void run() { 584 | try { 585 | // Wait for three connection attempts 586 | Thread.sleep(500); 587 | } catch (InterruptedException ex) { 588 | // ignore 589 | } 590 | mojo.setUrl(url); // Url fixed, next connection should be success 591 | } 592 | }) 593 | .start(); 594 | 595 | try { 596 | mojo.execute(); 597 | } catch (MojoExecutionException e) { 598 | fail("Connection was not restored: " + e.getMessage()); 599 | } 600 | 601 | assertTrue(mojo.getConnectionRetryAttempts() >= 1); 602 | assertTrue(mojo.isConnectionClosed()); 603 | } 604 | 605 | public void testConnectionRetryOnValidationError() { 606 | SqlExecMojo mojo = createMojo(); 607 | mojo.addText("select * from test32"); 608 | mojo.setConnectionValidationSqls(Arrays.asList("select 1 from test32")); 609 | mojo.setConnectionRetryCount(2); 610 | mojo.setConnectionRetryInterval(1); 611 | 612 | runSqlAfter(mojo, 1, Arrays.asList("create table test32 ( ID integer)")); 613 | 614 | try { 615 | mojo.execute(); 616 | } catch (MojoExecutionException e) { 617 | fail("Connection was not restored: " + e.getMessage()); 618 | } 619 | 620 | assertTrue(mojo.getConnectionRetryAttempts() >= 1); 621 | assertTrue(mojo.isConnectionClosed()); 622 | } 623 | 624 | public void testConnectionRetryOnValidationErrorMultipleValidationSql() { 625 | SqlExecMojo mojo = createMojo(); 626 | mojo.addText("select * from con_retry"); 627 | mojo.setConnectionValidationSqls(Arrays.asList("select 1 from con_retry", "select 1 from con_retry2")); 628 | mojo.setConnectionRetryCount(3); 629 | mojo.setConnectionRetryInterval(1); 630 | 631 | runSqlAfter(mojo, 1, Arrays.asList("create table con_retry ( ID integer)")); 632 | runSqlAfter(mojo, 2, Arrays.asList("create table con_retry2 ( ID integer)")); 633 | 634 | try { 635 | mojo.execute(); 636 | 637 | } catch (MojoExecutionException e) { 638 | fail("Connection was not restored: " + e.getMessage()); 639 | } 640 | 641 | assertTrue(mojo.getConnectionRetryAttempts() >= 2); 642 | assertTrue(mojo.isConnectionClosed()); 643 | } 644 | 645 | public void testValidationErrorMultipleValidationSql() { 646 | SqlExecMojo mojo = createMojo(); 647 | mojo.addText("select * from valid_err"); 648 | mojo.setConnectionValidationSqls(Arrays.asList("select 1 from valid_err", "select 1 from not")); 649 | mojo.setConnectionRetryCount(2); 650 | mojo.setConnectionRetryInterval(1); 651 | 652 | runSqlAfter(mojo, 1, Arrays.asList("create table valid_err ( ID integer)")); 653 | 654 | try { 655 | mojo.execute(); 656 | 657 | fail("Connection was restored"); 658 | } catch (MojoExecutionException e) { 659 | } 660 | 661 | assertTrue(mojo.getConnectionRetryAttempts() >= 2); 662 | assertTrue(mojo.isConnectionClosed()); 663 | } 664 | 665 | public void testCustomPrintResultSet() throws Exception { 666 | CustomSqlExecMojo customMojo = new CustomSqlExecMojo(); 667 | setUp(customMojo); 668 | 669 | String basedir = System.getProperty("basedir", "."); 670 | File outputFile = new File(basedir, "target/custom-print-resultset.out"); 671 | outputFile.delete(); 672 | customMojo.setOutputFile(outputFile); 673 | customMojo.setPrintResultSet(true); 674 | 675 | String command = "create table CUSTOM_PRINT ( PERSON_ID integer, FIRSTNAME varchar(50), LASTNAME varchar(50))"; 676 | customMojo.addText(command); 677 | customMojo.execute(); 678 | 679 | List list = Files.readAllLines(outputFile.toPath(), StandardCharsets.UTF_8); 680 | assertEquals(1, list.size()); 681 | assertEquals("0 cows affected", list.get(0)); 682 | 683 | customMojo.clear(); 684 | customMojo.setSqlCommand("insert into CUSTOM_PRINT (person_id) values (1)"); 685 | customMojo.execute(); 686 | 687 | list = Files.readAllLines(outputFile.toPath(), StandardCharsets.UTF_8); 688 | assertEquals(1, list.size()); 689 | assertEquals("1 cows affected", list.get(0)); 690 | 691 | customMojo.clear(); 692 | customMojo.setSqlCommand("select * from CUSTOM_PRINT"); 693 | customMojo.execute(); 694 | 695 | list = Files.readAllLines(outputFile.toPath(), StandardCharsets.UTF_8); 696 | assertEquals(2, list.size()); 697 | assertEquals("This is the way", list.get(0)); 698 | assertEquals("0 cows affected", list.get(1)); 699 | } 700 | 701 | public void testShowFooter() throws Exception { 702 | String basedir = System.getProperty("basedir", "."); 703 | File outputFile = new File(basedir, "target/show-footer.out"); 704 | outputFile.delete(); 705 | 706 | SqlExecMojo mojo = createMojo(); 707 | mojo.setShowFooter(false); 708 | mojo.setOutputFile(outputFile); 709 | mojo.setPrintResultSet(true); 710 | 711 | String command = "create table CUSTOM_PRINT ( PERSON_ID integer, FIRSTNAME varchar(50), LASTNAME varchar(50))"; 712 | mojo.addText(command); 713 | mojo.execute(); 714 | 715 | List list = Files.readAllLines(outputFile.toPath(), StandardCharsets.UTF_8); 716 | assertEquals(0, list.size()); 717 | 718 | mojo.clear(); 719 | mojo.setSqlCommand("insert into CUSTOM_PRINT (person_id) values (1)"); 720 | mojo.execute(); 721 | 722 | list = Files.readAllLines(outputFile.toPath(), StandardCharsets.UTF_8); 723 | assertEquals(0, list.size()); 724 | } 725 | 726 | private SqlExecMojo createMojo(String dbUrlPostfix) { 727 | SqlExecMojo mojo = createMojo(); 728 | mojo.setUrl(mojo.getUrl() + dbUrlPostfix); 729 | return mojo; 730 | } 731 | 732 | private SqlExecMojo createMojo() { 733 | SqlExecMojo mojo = new SqlExecMojo(); 734 | setUp(mojo); 735 | return mojo; 736 | } 737 | 738 | private String toTestUrl(String url) { 739 | return url.replaceAll(URL_REGEXP, "$1" + UUID.randomUUID().toString() + "$2"); 740 | } 741 | 742 | private void setUp(SqlExecMojo mojoToSetup) { 743 | 744 | // populate parameters 745 | mojoToSetup.setDriver(p.getProperty("driver")); 746 | mojoToSetup.setUsername(p.getProperty("user")); 747 | mojoToSetup.setPassword(p.getProperty("pasword")); 748 | mojoToSetup.setUrl(toTestUrl(p.getProperty("url"))); 749 | mojoToSetup.setDriverProperties(p.getProperty("driverProperties")); 750 | mojoToSetup.setSqlCommand(null); 751 | mojoToSetup.setDelimiter( 752 | SqlExecMojo.DEFAULT_DELIMITER); // This will simulate the defaultValue of @Parameter (...) 753 | mojoToSetup.setOnError(SqlExecMojo.ON_ERROR_ABORT); 754 | mojoToSetup.setDelimiterType(DelimiterType.NORMAL); 755 | mojoToSetup.setEscapeProcessing(true); 756 | mojoToSetup.setOutputDelimiter(","); 757 | mojoToSetup.setShowFooter(true); 758 | mojoToSetup.setShowHeaders(true); 759 | 760 | try { 761 | MavenFileFilter filter = 762 | (MavenFileFilter) lookup("org.apache.maven.shared.filtering.MavenFileFilter", "default"); 763 | mojoToSetup.setFileFilter(filter); 764 | 765 | SecDispatcher securityDispatcher = 766 | (SecDispatcher) lookup("org.sonatype.plexus.components.sec.dispatcher.SecDispatcher", "default"); 767 | mojoToSetup.setSecurityDispatcher(securityDispatcher); 768 | 769 | MavenProject project = new MavenProjectStub(); 770 | setVariableValueToObject(mojoToSetup, "project", project); 771 | } catch (ComponentLookupException | IllegalAccessException e) { 772 | throw new RuntimeException("Failed to setup mojo: " + e.getMessage(), e); 773 | } 774 | } 775 | 776 | public void testOutputFileEncoding() throws Exception { 777 | String command = "create table ENCODING ( PERSON_ID integer, FIRSTNAME varchar(50), LASTNAME varchar(50));\n" 778 | + "insert into ENCODING (PERSON_ID, FIRSTNAME, LASTNAME) values (1, 'A', 'B');"; 779 | 780 | SqlExecMojo mojo = createMojo(); 781 | mojo.addText(command); 782 | 783 | String basedir = System.getProperty("basedir", "."); 784 | File outputFile = new File(basedir, "target/sql-encoding.out"); 785 | outputFile.delete(); 786 | mojo.setOutputFile(outputFile); 787 | mojo.setPrintResultSet(true); 788 | 789 | mojo.execute(); 790 | 791 | assertTrue("Output file: " + outputFile + " not found.", outputFile.exists()); 792 | assertTrue("Unexpected empty output file. ", outputFile.length() > 0); 793 | 794 | List list = Files.readAllLines(outputFile.toPath(), StandardCharsets.UTF_8); 795 | assertTrue(list.size() == 2); 796 | assertEquals("0 rows affected", list.get(0)); 797 | assertEquals("1 rows affected", list.get(1)); 798 | } 799 | 800 | public void testOutputFileEncodingUtf16() throws Exception { 801 | String command = 802 | "create table ENCODING_UTF_16 ( PERSON_ID integer, FIRSTNAME varchar(50), LASTNAME varchar(50));\n" 803 | + "insert into ENCODING_UTF_16 (PERSON_ID, FIRSTNAME, LASTNAME) values (1, 'A', 'B');"; 804 | 805 | SqlExecMojo mojo = createMojo(); 806 | mojo.addText(command); 807 | 808 | String basedir = System.getProperty("basedir", "."); 809 | File outputFile = new File(basedir, "target/sql-encoding-utf-16.out"); 810 | outputFile.delete(); 811 | mojo.setOutputFile(outputFile); 812 | mojo.setOutputEncoding("UTF-16"); 813 | mojo.setPrintResultSet(true); 814 | 815 | mojo.execute(); 816 | 817 | assertTrue("Output file: " + outputFile + " not found.", outputFile.exists()); 818 | assertTrue("Unexpected empty output file. ", outputFile.length() > 0); 819 | 820 | List list = Files.readAllLines(outputFile.toPath(), StandardCharsets.UTF_16); 821 | assertTrue(list.size() == 2); 822 | assertEquals("0 rows affected", list.get(0)); 823 | assertEquals("1 rows affected", list.get(1)); 824 | } 825 | 826 | public void testMysqlDelimiter() throws MojoExecutionException { 827 | File[] srcFiles = new File[4]; 828 | srcFiles[0] = new File("src/test/data/delimiter-a.sql"); 829 | srcFiles[1] = new File("src/test/data/delimiter-b.sql"); 830 | srcFiles[2] = new File("src/test/data/delimiter-c.sql"); 831 | srcFiles[3] = new File("src/test/data/create-test-tables.sql"); 832 | 833 | SqlExecMojo mojo = createMojo(); 834 | mojo.setSrcFiles(srcFiles); 835 | mojo.execute(); 836 | 837 | assertEquals(9, mojo.getSuccessfulStatements()); 838 | } 839 | 840 | private void runSqlAfter(SqlExecMojo mojo, int secs, final List sqls) { 841 | new Thread(new Runnable() { 842 | @Override 843 | public void run() { 844 | try { 845 | // Wait for three connection attempts 846 | Thread.sleep(secs * 1000); 847 | } catch (InterruptedException ex) { 848 | } 849 | 850 | Connection conn = null; 851 | 852 | try { 853 | conn = mojo.getConnection(); 854 | 855 | try (Statement stmt = conn.createStatement()) { 856 | for (String sql : sqls) { 857 | stmt.execute(sql); 858 | } 859 | } 860 | } catch (Exception e) { 861 | fail(e.getMessage()); 862 | } finally { 863 | mojo.closeConnection(); 864 | } 865 | } 866 | }) 867 | .start(); 868 | } 869 | } 870 | -------------------------------------------------------------------------------- /src/main/java/org/codehaus/mojo/sql/SqlExecMojo.java: -------------------------------------------------------------------------------- 1 | package org.codehaus.mojo.sql; 2 | 3 | /* 4 | * Licensed to the Apache Software Foundation (ASF) under one 5 | * or more contributor license agreements. See the NOTICE file 6 | * distributed with this work for additional information 7 | * regarding copyright ownership. The ASF licenses this file 8 | * to you under the Apache License, Version 2.0 (the 9 | * "License"); you may not use this file except in compliance 10 | * with the License. You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, 15 | * software distributed under the License is distributed on an 16 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | * KIND, either express or implied. See the License for the 18 | * specific language governing permissions and limitations 19 | * under the License. 20 | */ 21 | 22 | import java.io.BufferedOutputStream; 23 | import java.io.BufferedReader; 24 | import java.io.File; 25 | import java.io.FileOutputStream; 26 | import java.io.FileReader; 27 | import java.io.IOException; 28 | import java.io.InputStreamReader; 29 | import java.io.PrintStream; 30 | import java.io.Reader; 31 | import java.io.StringReader; 32 | import java.nio.file.Files; 33 | import java.sql.Connection; 34 | import java.sql.Driver; 35 | import java.sql.ResultSet; 36 | import java.sql.ResultSetMetaData; 37 | import java.sql.SQLException; 38 | import java.sql.SQLWarning; 39 | import java.sql.Statement; 40 | import java.util.Collections; 41 | import java.util.HashMap; 42 | import java.util.List; 43 | import java.util.Map; 44 | import java.util.Properties; 45 | import java.util.StringTokenizer; 46 | import java.util.Vector; 47 | 48 | import org.apache.commons.text.StringEscapeUtils; 49 | import org.apache.maven.execution.MavenSession; 50 | import org.apache.maven.plugin.AbstractMojo; 51 | import org.apache.maven.plugin.MojoExecutionException; 52 | import org.apache.maven.plugins.annotations.Component; 53 | import org.apache.maven.plugins.annotations.Mojo; 54 | import org.apache.maven.plugins.annotations.Parameter; 55 | import org.apache.maven.project.MavenProject; 56 | import org.apache.maven.settings.Server; 57 | import org.apache.maven.settings.Settings; 58 | import org.apache.maven.shared.filtering.MavenFileFilter; 59 | import org.apache.maven.shared.filtering.MavenFileFilterRequest; 60 | import org.apache.maven.shared.filtering.MavenFilteringException; 61 | import org.apache.maven.shared.scriptinterpreter.ScriptException; 62 | import org.apache.maven.shared.scriptinterpreter.ScriptRunner; 63 | import org.codehaus.plexus.util.FileUtils; 64 | import org.codehaus.plexus.util.IOUtil; 65 | import org.codehaus.plexus.util.StringUtils; 66 | import org.sonatype.plexus.components.sec.dispatcher.SecDispatcher; 67 | import org.sonatype.plexus.components.sec.dispatcher.SecDispatcherException; 68 | 69 | /** 70 | * Executes SQL against a database. 71 | */ 72 | @Mojo(name = "execute", requiresProject = true, threadSafe = true) 73 | public class SqlExecMojo extends AbstractMojo { 74 | 75 | private static final String DELIMITER_STATEMENT = "DELIMITER "; 76 | private static final int DELIMITER_STATEMENT_LENGTH = DELIMITER_STATEMENT.length(); 77 | 78 | /** 79 | * Call {@link #setOnError(String)} with this value to abort SQL command execution if an error is found. 80 | */ 81 | public static final String ON_ERROR_ABORT = "abort"; 82 | 83 | /** 84 | * Call {@link #setOnError(String)} with this value to continue SQL command execution until all commands have been 85 | * attempted, then abort the build if an SQL error occurred in any of the commands. 86 | */ 87 | public static final String ON_ERROR_ABORT_AFTER = "abortAfter"; 88 | 89 | /** 90 | * Call {@link #setOnError(String)} with this value to continue SQL command execution if an error is found. 91 | */ 92 | public static final String ON_ERROR_CONTINUE = "continue"; 93 | 94 | /** 95 | * Call {@link #setOrderFile(String)} with this value to sort in ascendant order the sql files. 96 | */ 97 | public static final String FILE_SORTING_ASC = "ascending"; 98 | 99 | /** 100 | * Call {@link #setOrderFile(String)} with this value to sort in descendant order the sql files. 101 | */ 102 | public static final String FILE_SORTING_DSC = "descending"; 103 | 104 | /** 105 | * The default SQL delimiter which is used to separate statements. 106 | */ 107 | public static final String DEFAULT_DELIMITER = ";"; 108 | 109 | //////////////////////////// User Info /////////////////////////////////// 110 | 111 | /** 112 | * Database username. If not given, it will be looked up through settings.xml's server with 113 | * ${settingsKey} as key. 114 | * 115 | * @since 1.0 116 | */ 117 | @Parameter(property = "username") 118 | private String username; 119 | 120 | /** 121 | * Database password. If not given, it will be looked up through settings.xml's server with 122 | * ${settingsKey} as key. 123 | * 124 | * @since 1.0 125 | */ 126 | @Parameter(property = "password") 127 | private String password; 128 | 129 | /** 130 | * Ignore the password and use anonymous access. This may be useful for databases like MySQL which do not allow 131 | * empty password parameters in the connection initialization. 132 | * 133 | * @since 1.4 134 | */ 135 | @Parameter(defaultValue = "false") 136 | private boolean enableAnonymousPassword; 137 | 138 | /** 139 | * Additional key=value pairs separated by comma to be passed into JDBC driver. 140 | * 141 | * @since 1.0 142 | */ 143 | @Parameter(defaultValue = "", property = "driverProperties") 144 | private String driverProperties; 145 | 146 | /** 147 | * @since 1.0 148 | */ 149 | @Parameter(defaultValue = "${settings}", readonly = true, required = true) 150 | private Settings settings; 151 | 152 | /** 153 | * Server's id in settings.xml to look up username and password. Defaults to 154 | * ${url} if not given. 155 | * 156 | * @since 1.0 157 | */ 158 | @Parameter(property = "settingsKey") 159 | private String settingsKey; 160 | 161 | /** 162 | * MNG-4384 163 | * 164 | * @since 1.5 165 | */ 166 | @Component(role = SecDispatcher.class, hint = "default") 167 | private SecDispatcher securityDispatcher; 168 | 169 | /** 170 | * Skip execution when there is an error obtaining a connection. This is a special case to support databases, such 171 | * as embedded Derby, that can shutdown the database via the URL (i.e. shutdown=true). 172 | * 173 | * @since 1.1 174 | */ 175 | @Parameter(defaultValue = "false", property = "skipOnConnectionError") 176 | private boolean skipOnConnectionError; 177 | 178 | /** 179 | * Skip missing files defined by {@link #setSrcFiles(File[])}. This behavior allows to define a full fledged list 180 | * of all sql files in a single {@code pom.xml} without failing if used by modules for which some sql files are not 181 | * available on the classpath. 182 | */ 183 | @Parameter(defaultValue = "false", property = "skipMissingFiles") 184 | private boolean skipMissingFiles; 185 | 186 | /** 187 | * Setting this parameter to true will force the execution of this mojo, even if it would get skipped 188 | * usually. 189 | */ 190 | @Parameter(defaultValue = "false", property = "forceOpenJpaExecution", required = true) 191 | private boolean forceMojoExecution; 192 | 193 | /** 194 | * The Maven Project Object 195 | */ 196 | @Parameter(defaultValue = "${project}", readonly = true, required = true) 197 | private MavenProject project; 198 | 199 | /** 200 | */ 201 | @Parameter(defaultValue = "${session}", readonly = true, required = true) 202 | private MavenSession mavenSession; 203 | 204 | //////////////////////////////// Source info ///////////////////////////// 205 | 206 | /** 207 | * SQL input commands separated by ${delimiter}. 208 | * 209 | * @since 1.0 210 | */ 211 | @Parameter(property = "sqlCommand") 212 | private String sqlCommand; 213 | 214 | /** 215 | * List of files containing SQL statements to load. 216 | * 217 | * @since 1.0 218 | * @see #fileset 219 | */ 220 | @Parameter 221 | private File[] srcFiles; 222 | 223 | /** 224 | * File(s) containing SQL statements to load. Only use a Fileset if you want to use ant-like filepatterns, otherwise 225 | * use srcFiles. The order is based on a matching occurrence while scanning the directory (not the order of 226 | * includes!). 227 | * 228 | * @since 1.0 229 | * @see #srcFiles 230 | */ 231 | @Parameter 232 | private Fileset fileset; 233 | 234 | /** 235 | * When true, skip the execution. 236 | * 237 | * @since 1.0 238 | */ 239 | @Parameter(defaultValue = "false") 240 | private boolean skip; 241 | 242 | ////////////////////////////////// Database info ///////////////////////// 243 | /** 244 | * Database URL. 245 | * 246 | * @since 1.0-beta-1 247 | */ 248 | @Parameter(property = "url", required = true) 249 | private String url; 250 | 251 | /** 252 | * Database driver classname. 253 | * 254 | * @since 1.0 255 | */ 256 | @Parameter(property = "driver", required = true) 257 | private String driver; 258 | 259 | ////////////////////////////// Operation Configuration //////////////////// 260 | /** 261 | * Set to true to execute none-transactional SQL. 262 | * 263 | * @since 1.0 264 | */ 265 | @Parameter(defaultValue = "false", property = "autocommit") 266 | private boolean autocommit; 267 | 268 | /** 269 | * Set to true to execute immediately rollback transactional SQL. 270 | * 271 | * @since 3.0.0 272 | */ 273 | @Parameter(defaultValue = "false", property = "rollbackTransactions") 274 | private boolean rollbackTransactions; 275 | 276 | /** 277 | * Action to perform if an error is found. Possible values are abort and continue. 278 | * 279 | * @since 1.0 280 | */ 281 | @Parameter(defaultValue = ON_ERROR_ABORT, property = "onError") 282 | private String onError; 283 | 284 | /** 285 | * List of connection validation SQLs. If the value is given, the SQL files 286 | * are processed after all validation have been executed successfully. 287 | * The validation SQLs can be used to verify that required tables or data 288 | * exists before the SQLs are processed. 289 | * 290 | * @since 3.0.0 291 | */ 292 | @Parameter(defaultValue = "", property = "connectionValidationSqls") 293 | private List connectionValidationSqls; 294 | 295 | /** 296 | * Connection retry count. How many times connection is tried to be 297 | * opened and validated after failure. 298 | * 299 | * @since 3.0.0 300 | */ 301 | @Parameter(defaultValue = "0", property = "connectionRetryCount") 302 | private int connectionRetryCount; 303 | 304 | /** 305 | * How many seconds are waited before next connection attempt. 306 | * 307 | * @since 3.0.0 308 | */ 309 | @Parameter(defaultValue = "1", property = "connectionRetryInterval") 310 | private int connectionRetryInterval = 1; 311 | 312 | ////////////////////////////// Parser Configuration //////////////////// 313 | 314 | /** 315 | * Set the delimiter that separates SQL statements. 316 | * 317 | * @since 1.0 318 | */ 319 | @Parameter(defaultValue = DEFAULT_DELIMITER, property = "delimiter") 320 | private String delimiter; 321 | 322 | /** 323 | *

324 | * The delimiter type takes two values - "normal" and "row". Normal means that any occurrence of the delimiter 325 | * terminate the SQL command whereas with row, only a line containing just the delimiter is recognized as the end of 326 | * the command. 327 | *

328 | *

329 | * For example, set this to "go" and delimiterType to "row" for Sybase ASE or MS SQL Server. 330 | *

331 | * 332 | * @since 1.2 333 | */ 334 | @Parameter(defaultValue = DelimiterType.NORMAL, property = "delimiterType") 335 | private String delimiterType; 336 | 337 | /** 338 | * Set the order in which the SQL files will be executed. Possible values are ascending and 339 | * descending. Any other value means that no sorting will be performed. Refers to {@link #fileset} and 340 | * {@link #srcFiles} 341 | * 342 | * @since 1.1 343 | */ 344 | @Parameter(property = "orderFile") 345 | private String orderFile; 346 | 347 | /** 348 | * Keep the format of an SQL block. 349 | * 350 | * @since 1.1 351 | */ 352 | @Parameter(defaultValue = "false", property = "keepFormat") 353 | private boolean keepFormat; 354 | 355 | /////////////////////////////////////////////////////////////////////////////////////// 356 | /** 357 | * Print SQL results. 358 | * 359 | * @since 1.3 360 | */ 361 | @Parameter(defaultValue = "false", property = "printResultSet") 362 | private boolean printResultSet; 363 | 364 | /** 365 | * Print header columns. 366 | */ 367 | @Parameter(property = "showheaders", defaultValue = "true") 368 | private boolean showHeaders; 369 | 370 | /** 371 | * Print footer value, informing on the number of rows 372 | */ 373 | @Parameter(property = "showFooter", defaultValue = "true") 374 | private boolean showFooter; 375 | 376 | /** 377 | * Dump the SQL execution's output to a file.
378 | * Default value is: System.out. 379 | * 380 | * @since 1.3 381 | */ 382 | @Parameter 383 | private File outputFile; 384 | 385 | /** 386 | * The delimiter used to separate fields in the output when using printResultSet. 387 | * 388 | * @since 1.4 389 | */ 390 | @Parameter(defaultValue = ",") 391 | private String outputDelimiter; 392 | 393 | /** 394 | * Encoding to use while writing queried data to a file. 395 | * 396 | * @since 3.0.0 397 | */ 398 | @Parameter(defaultValue = "${project.build.sourceEncoding}", property = "outputEncoding") 399 | private String outputEncoding; 400 | 401 | /** 402 | * Encoding to use when reading SQL statements from a file. 403 | * 404 | * @since 1.1 405 | */ 406 | @Parameter(defaultValue = "${project.build.sourceEncoding}", property = "encoding") 407 | private String encoding; 408 | 409 | /** 410 | * Append to an existing file or overwrite it? 411 | */ 412 | private boolean append = false; 413 | 414 | /** 415 | * Argument to Statement.setEscapeProcessing If you want the driver to use regular SQL syntax then set this to 416 | * false. 417 | * 418 | * @since 1.4 419 | */ 420 | @Parameter(defaultValue = "true", property = "escapeProcessing") 421 | private boolean escapeProcessing; 422 | 423 | ////////////////////////////////// Internal properties////////////////////// 424 | 425 | /** 426 | * number of successful executed statements 427 | */ 428 | private int successfulStatements = 0; 429 | 430 | /** 431 | * number of total executed statements 432 | */ 433 | private int totalStatements = 0; 434 | 435 | /** 436 | * Database connection 437 | */ 438 | private Connection conn = null; 439 | 440 | /** 441 | * SQL statement 442 | */ 443 | private Statement statement = null; 444 | 445 | /** 446 | * SQL transactions to perform 447 | */ 448 | private List transactions = new Vector<>(); 449 | 450 | /** 451 | * @since 1.4 452 | */ 453 | @Component(role = MavenFileFilter.class) 454 | private MavenFileFilter fileFilter; 455 | 456 | /** 457 | * Set to true if you want to filter the srcFiles using system-, user- and project properties 458 | * 459 | * @since 1.4 460 | */ 461 | @Parameter(defaultValue = "false", property = "enableFiltering") 462 | private boolean enableFiltering; 463 | 464 | private ScriptRunner scriptRunner; 465 | 466 | /** 467 | * @since 1.6 468 | */ 469 | @Parameter 470 | private File preExecuteHookScript; 471 | 472 | /** 473 | * @since 1.6 474 | */ 475 | @Parameter 476 | private File postExecuteHookScript; 477 | 478 | /** 479 | * number of done connection retry attempts 480 | * 481 | * @since 3.0.0 482 | */ 483 | private int connectionRetryAttempts; 484 | 485 | /** 486 | * Add a SQL transaction to execute 487 | * 488 | * @return a new SqlExecMojo.Transaction 489 | */ 490 | public Transaction createTransaction() { 491 | Transaction t = new Transaction(); 492 | transactions.add(t); 493 | return t; 494 | } 495 | 496 | /** 497 | * Set an inline SQL command to execute. NB: Properties are not expanded in this text. 498 | * 499 | * @param sql the sql statement to add 500 | */ 501 | public void addText(String sql) { 502 | if (this.sqlCommand == null) { 503 | this.sqlCommand = sql; 504 | } else { 505 | this.sqlCommand += sql; 506 | } 507 | } 508 | 509 | /** 510 | * Set the file encoding to use on the SQL files read in 511 | * 512 | * @param encoding the encoding to use on the files 513 | */ 514 | public void setEncoding(String encoding) { 515 | this.encoding = encoding; 516 | } 517 | 518 | /** 519 | * Set the delimiter that separates SQL statements. Defaults to ";"; 520 | * 521 | * @param delimiter the new delimiter 522 | */ 523 | public void setDelimiter(String delimiter) { 524 | this.delimiter = delimiter; 525 | } 526 | 527 | /** 528 | * Set the delimiter type: "normal" or "row" (default "normal"). 529 | * 530 | * @param delimiterType the new delimiterType 531 | */ 532 | public void setDelimiterType(String delimiterType) { 533 | this.delimiterType = delimiterType; 534 | } 535 | 536 | /** 537 | * Print result sets from the statements; optional, default false 538 | * 539 | * @param print true to print the resultset, otherwise false 540 | */ 541 | public void setPrintResultSet(boolean print) { 542 | this.printResultSet = print; 543 | } 544 | 545 | /** 546 | * Print headers for result sets from the statements; optional, default true. 547 | * 548 | * @param showHeaders true to show the headers, otherwise false 549 | */ 550 | public void setShowHeaders(boolean showHeaders) { 551 | this.showHeaders = showHeaders; 552 | } 553 | 554 | /** 555 | * Set the output file; 556 | * 557 | * @param output the output file 558 | */ 559 | public void setOutputFile(File output) { 560 | this.outputFile = output; 561 | } 562 | 563 | /** 564 | * whether output should be appended to or overwrite an existing file. Defaults to false. 565 | * 566 | * @param append true to append, otherwise false to overwrite 567 | */ 568 | public void setAppend(boolean append) { 569 | this.append = append; 570 | } 571 | 572 | /** 573 | * whether or not format should be preserved. Defaults to false. 574 | * 575 | * @param keepformat {@code true} to keep the format {@code false} otherwise. 576 | */ 577 | public void setKeepFormat(boolean keepformat) { 578 | this.keepFormat = keepformat; 579 | } 580 | 581 | /** 582 | * Set escape processing for statements. 583 | * 584 | * @param enable true to escape, otherwise false 585 | */ 586 | public void setEscapeProcessing(boolean enable) { 587 | escapeProcessing = enable; 588 | } 589 | 590 | /** 591 | *

592 | * Determine if the mojo execution should get skipped. 593 | *

594 | * This is the case if: 595 | *
    596 | *
  • {@link #skip} is true
  • 597 | *
  • if the mojo gets executed on a project with packaging type 'pom' and {@link #forceMojoExecution} is 598 | * false
  • 599 | *
600 | * 601 | * @return true if the mojo execution should be skipped. 602 | */ 603 | protected boolean skipMojo() { 604 | if (skip) { 605 | getLog().info("User has requested to skip execution."); 606 | return true; 607 | } 608 | 609 | if (!forceMojoExecution && project != null && "pom".equals(project.getPackaging())) { 610 | getLog().info("Skipping sql execution for project with packaging type 'pom'"); 611 | return true; 612 | } 613 | 614 | return false; 615 | } 616 | 617 | /** 618 | * Load the sql file and then execute it 619 | * 620 | * @throws MojoExecutionException 621 | */ 622 | @Override 623 | public void execute() throws MojoExecutionException { 624 | 625 | if (skipMojo()) { 626 | return; 627 | } 628 | 629 | executeScriptPlusSql(); 630 | } 631 | 632 | private void executeScriptPlusSql() throws MojoExecutionException { 633 | // prepare scriptrunner 634 | scriptRunner = new ScriptRunner(); 635 | scriptRunner.setScriptEncoding(encoding); 636 | // scriptRunner.setGlobalVariable( "localRepositoryPath", localRepositoryPath ); 637 | // scriptRunner.setClassPath( scriptClassPath ); 638 | 639 | Map context = new HashMap<>(); 640 | 641 | try { 642 | if (preExecuteHookScript != null) { 643 | scriptRunner.run("pre-execute script", preExecuteHookScript, context, null); 644 | } 645 | 646 | executeSqlCore(); 647 | } catch (IOException | ScriptException e) { 648 | throw new MojoExecutionException(e.getMessage(), e); 649 | } finally { 650 | try { 651 | if (postExecuteHookScript != null) { 652 | scriptRunner.run("post-execute script", postExecuteHookScript, context, null); 653 | } 654 | } catch (IOException | ScriptException e) { 655 | throw new MojoExecutionException(e.getMessage(), e); 656 | } 657 | } 658 | } 659 | 660 | protected void executeSqlCore() throws MojoExecutionException { 661 | connectionRetryAttempts = 0; 662 | successfulStatements = 0; 663 | totalStatements = 0; 664 | 665 | // Connection is not valid until it is proved to be 666 | boolean connectionIsValid = false; 667 | 668 | loadUserInfoFromSettings(); 669 | 670 | addCommandToTransactions(); 671 | 672 | addFilesToTransactions(); 673 | 674 | addFileSetToTransactions(); 675 | 676 | sortTransactions(); 677 | 678 | // Loop until connection is valid (or exited otherwise) 679 | while (!connectionIsValid) { 680 | 681 | // Check should we retry, if there are some errors 682 | boolean retryOnConnectionError = this.connectionRetryCount > connectionRetryAttempts; 683 | 684 | try { 685 | // Get a new connection if is not already open 686 | if (conn == null || conn.isClosed()) { 687 | conn = getConnection(); 688 | } 689 | 690 | validateConnection(conn); 691 | 692 | // No SQLException thrown, the connection should be fine 693 | connectionIsValid = true; 694 | } catch (SQLException e) { 695 | if (retryOnConnectionError) { 696 | // User want to retry connection, increase the retry attempts 697 | connectionRetryAttempts++; 698 | getLog().info("Connection validation failed: retrying connection in " + connectionRetryInterval 699 | + " secs (" + connectionRetryAttempts + "/" + connectionRetryCount + ")..."); 700 | waitToRetryConnectionValidation(); 701 | } else if (!this.skipOnConnectionError) { 702 | // Make sure connection is closed, it can be open if only validation failed 703 | closeConnection(); 704 | 705 | throw new MojoExecutionException(e.getMessage(), e); 706 | } else { 707 | // Make sure connection is closed, it can be open if only validation failed 708 | closeConnection(); 709 | 710 | // Error on get connection and user asked to skip the rest 711 | return; 712 | } 713 | } 714 | } 715 | 716 | try { 717 | statement = conn.createStatement(); 718 | statement.setEscapeProcessing(escapeProcessing); 719 | 720 | PrintStream out = System.out; 721 | try { 722 | if (outputFile != null) { 723 | getLog().debug("Opening PrintStream to output file " + outputFile); 724 | outputFile.getParentFile().mkdirs(); 725 | 726 | if (StringUtils.isEmpty(this.outputEncoding)) { 727 | this.outputEncoding = System.getProperty("file.encoding"); 728 | } 729 | 730 | out = new PrintStream( 731 | new BufferedOutputStream(new FileOutputStream(outputFile.getAbsolutePath(), append)), 732 | true, 733 | this.outputEncoding); 734 | } 735 | 736 | // Process all transactions 737 | for (Transaction t : transactions) { 738 | t.runTransaction(out); 739 | 740 | if (!autocommit) { 741 | if (rollbackTransactions) { 742 | getLog().debug("Rollback transaction"); 743 | conn.rollback(); 744 | } else { 745 | getLog().debug("Committing transaction"); 746 | conn.commit(); 747 | } 748 | } 749 | } 750 | } finally { 751 | if (out != null && out != System.out) { 752 | out.close(); 753 | } 754 | } 755 | } catch (IOException e) { 756 | throw new MojoExecutionException(e.getMessage(), e); 757 | } catch (SQLException e) { 758 | if (!autocommit && conn != null && ON_ERROR_ABORT.equalsIgnoreCase(getOnError())) { 759 | try { 760 | conn.rollback(); 761 | } catch (SQLException ex) { 762 | // ignore 763 | } 764 | } 765 | throw new MojoExecutionException(e.getMessage(), e); 766 | } finally { 767 | closeStatement(); 768 | closeConnection(); 769 | } 770 | 771 | getLog().info(getSuccessfulStatements() + " of " + getTotalStatements() 772 | + " SQL statements executed successfully"); 773 | 774 | if (ON_ERROR_ABORT_AFTER.equalsIgnoreCase(getOnError()) && totalStatements != successfulStatements) { 775 | throw new MojoExecutionException("Some SQL statements failed to execute"); 776 | } 777 | } 778 | 779 | /** 780 | * Add sql command to transactions list. 781 | */ 782 | private void addCommandToTransactions() { 783 | if (sqlCommand != null) { 784 | createTransaction().addText(sqlCommand.trim()); 785 | } 786 | } 787 | 788 | /** 789 | * Add user sql fileset to transation list 790 | */ 791 | private void addFileSetToTransactions() { 792 | String[] includedFiles; 793 | if (fileset != null) { 794 | fileset.scan(); 795 | includedFiles = fileset.getIncludedFiles(); 796 | } else { 797 | includedFiles = new String[0]; 798 | } 799 | 800 | for (String includedFile : includedFiles) { 801 | createTransaction().setSrc(new File(fileset.getBasedir(), includedFile)); 802 | } 803 | } 804 | 805 | /** 806 | * Add user input of srcFiles to transaction list. 807 | * 808 | * @throws MojoExecutionException 809 | */ 810 | private void addFilesToTransactions() throws MojoExecutionException { 811 | File[] files = getSrcFiles(); 812 | 813 | MavenFileFilterRequest request = new MavenFileFilterRequest(); 814 | request.setEncoding(encoding); 815 | request.setMavenSession(mavenSession); 816 | request.setMavenProject(project); 817 | request.setFiltering(enableFiltering); 818 | if (files != null) { 819 | for (File sourceFile : files) { 820 | if (sourceFile != null && !sourceFile.exists()) { 821 | if (skipMissingFiles) { 822 | getLog().debug(String.format("ignoring non existing sql file [%s].", sourceFile.getPath())); 823 | continue; 824 | } 825 | throw new MojoExecutionException(sourceFile.getPath() + " not found."); 826 | } 827 | 828 | String basename = FileUtils.basename(sourceFile.getName()); 829 | String extension = FileUtils.extension(sourceFile.getName()); 830 | File targetFile = FileUtils.createTempFile(basename, extension, null); 831 | if (!getLog().isDebugEnabled()) { 832 | targetFile.deleteOnExit(); 833 | } 834 | 835 | request.setFrom(sourceFile); 836 | request.setTo(targetFile); 837 | 838 | try { 839 | fileFilter.copyFile(request); 840 | } catch (MavenFilteringException e) { 841 | throw new MojoExecutionException(e.getMessage()); 842 | } 843 | 844 | createTransaction().setSrc(targetFile); 845 | } 846 | } 847 | } 848 | 849 | /** 850 | * Sort the transaction list. 851 | */ 852 | private void sortTransactions() { 853 | if (FILE_SORTING_ASC.equalsIgnoreCase(this.orderFile)) { 854 | Collections.sort(transactions); 855 | } else if (FILE_SORTING_DSC.equalsIgnoreCase(this.orderFile)) { 856 | transactions.sort(Collections.reverseOrder()); 857 | } 858 | } 859 | 860 | /** 861 | * Load username password from settings if user has not set them in JVM properties 862 | * 863 | * @throws MojoExecutionException 864 | */ 865 | private void loadUserInfoFromSettings() throws MojoExecutionException { 866 | if (this.settingsKey == null) { 867 | this.settingsKey = getUrl(); 868 | } 869 | 870 | if ((getUsername() == null || getPassword() == null) && (settings != null)) { 871 | Server server = this.settings.getServer(this.settingsKey); 872 | 873 | if (server != null) { 874 | if (getUsername() == null) { 875 | setUsername(server.getUsername()); 876 | } 877 | 878 | if (getPassword() == null && server.getPassword() != null) { 879 | try { 880 | setPassword(securityDispatcher.decrypt(server.getPassword())); 881 | } catch (SecDispatcherException e) { 882 | throw new MojoExecutionException(e.getMessage()); 883 | } 884 | } 885 | } 886 | } 887 | 888 | if (getUsername() == null) { 889 | // allow empty username 890 | setUsername(""); 891 | } 892 | 893 | if (getPassword() == null) { 894 | // allow empty password 895 | setPassword(""); 896 | } 897 | } 898 | 899 | /** 900 | * Creates a new Connection as using the driver, url, userid and password specified. The calling method is 901 | * responsible for closing the connection. 902 | * 903 | * @return Connection the newly created connection. 904 | * @throws MojoExecutionException if the UserId/Password/Url is not set or there is no suitable driver or the driver 905 | * fails to load. 906 | * @throws SQLException if there is problem getting connection with valid url 907 | */ 908 | Connection getConnection() throws MojoExecutionException, SQLException { 909 | getLog().debug("connecting to " + getUrl()); 910 | Properties info = new Properties(); 911 | info.put("user", getUsername()); 912 | 913 | if (!enableAnonymousPassword) { 914 | info.put("password", getPassword()); 915 | } 916 | 917 | info.putAll(this.getDriverProperties()); 918 | 919 | Driver driverInstance; 920 | 921 | try { 922 | Class dc = Class.forName(getDriver()); 923 | driverInstance = (Driver) dc.getDeclaredConstructor().newInstance(); 924 | } catch (ClassNotFoundException e) { 925 | throw new MojoExecutionException("Driver class not found: " + getDriver(), e); 926 | } catch (Exception e) { 927 | throw new MojoExecutionException("Failure loading driver: " + getDriver(), e); 928 | } 929 | 930 | Connection connection = driverInstance.connect(getUrl(), info); 931 | 932 | if (connection == null) { 933 | // Driver doesn't understand the URL 934 | throw new SQLException("No suitable Driver for " + getUrl()); 935 | } 936 | 937 | connection.setAutoCommit(autocommit); 938 | return connection; 939 | } 940 | 941 | /** 942 | * parse driverProperties into Properties set 943 | * 944 | * @return the driver properties 945 | * @throws MojoExecutionException 946 | */ 947 | protected Properties getDriverProperties() throws MojoExecutionException { 948 | Properties properties = new Properties(); 949 | 950 | if (!StringUtils.isEmpty(this.driverProperties)) { 951 | String[] tokens = StringUtils.split(this.driverProperties, ","); 952 | for (String token : tokens) { 953 | String[] keyValueTokens = StringUtils.split(token.trim(), "="); 954 | if (keyValueTokens.length != 2) { 955 | throw new MojoExecutionException("Invalid JDBC Driver properties: " + this.driverProperties); 956 | } 957 | 958 | properties.setProperty(keyValueTokens[0], keyValueTokens[1]); 959 | } 960 | } 961 | 962 | return properties; 963 | } 964 | 965 | /** 966 | * read in lines and execute them 967 | * 968 | * @param reader the reader 969 | * @param out the outputstream 970 | * @throws SQLException 971 | * @throws IOException 972 | */ 973 | private void runStatements(Reader reader, PrintStream out) throws SQLException, IOException { 974 | String line; 975 | 976 | // The delimeter can be overwritten by mysql DELIMETER command. 977 | // If the delimeter is overwritten it is in one file, not a global change 978 | String fileDelimeter = this.delimiter; 979 | 980 | // TODO: Check if this equivalent with if (enableBlockMode) {.. 981 | if (delimiterType.equals(DelimiterType.ROW)) { 982 | // no need to parse the content, ship it directly to jdbc in one sql statement 983 | line = IOUtil.toString(reader); 984 | execSQL(line, out); 985 | return; 986 | } 987 | 988 | StringBuilder sql = new StringBuilder(); 989 | BufferedReader in = new BufferedReader(reader); 990 | int overflow = SqlSplitter.NO_END; 991 | 992 | while ((line = in.readLine()) != null) { 993 | if (!keepFormat) { 994 | line = line.trim(); 995 | } 996 | 997 | if (!keepFormat) { 998 | if (line.startsWith("//")) { 999 | continue; 1000 | } 1001 | if (line.startsWith("--")) { 1002 | continue; 1003 | } 1004 | StringTokenizer st = new StringTokenizer(line); 1005 | if (st.hasMoreTokens()) { 1006 | String token = st.nextToken(); 1007 | if ("REM".equalsIgnoreCase(token)) { 1008 | continue; 1009 | } 1010 | } 1011 | } 1012 | 1013 | // Check for mysql delimiter statements 1014 | if (overflow >= SqlSplitter.NO_END) { 1015 | String ucLine = line.toUpperCase(); 1016 | if (ucLine.startsWith(DELIMITER_STATEMENT)) { 1017 | fileDelimeter = line.substring(DELIMITER_STATEMENT_LENGTH).trim(); 1018 | continue; 1019 | } 1020 | } 1021 | 1022 | if (!keepFormat) { 1023 | sql.append(" ").append(line); 1024 | } else { 1025 | sql.append("\n").append(line); 1026 | } 1027 | 1028 | overflow = SqlSplitter.containsSqlEnd(line, fileDelimeter, overflow); 1029 | 1030 | // SQL defines "--" as a comment to EOL 1031 | // and in Oracle it may contain a hint 1032 | // so we cannot just remove it, instead we must end it 1033 | if (!keepFormat && overflow == SqlSplitter.NO_END) { 1034 | sql.append("\n"); 1035 | } 1036 | 1037 | if ((delimiterType.equals(DelimiterType.NORMAL) && overflow > 0) 1038 | || (delimiterType.equals(DelimiterType.ROW) && line.trim().equals(fileDelimeter))) { 1039 | execSQL(sql.substring(0, sql.length() - fileDelimeter.length()), out); 1040 | sql.setLength(0); // clean buffer 1041 | overflow = SqlSplitter.NO_END; 1042 | } 1043 | } 1044 | 1045 | // Catch any statements not followed by ; 1046 | if (sql.length() > 0) { 1047 | execSQL(sql.toString(), out); 1048 | } 1049 | } 1050 | 1051 | /** 1052 | * Exec the sql statement. 1053 | * 1054 | * @param sql query to execute 1055 | * @param out the outputstream 1056 | */ 1057 | private void execSQL(String sql, PrintStream out) throws SQLException { 1058 | // Check and ignore empty statements 1059 | if (sql.trim().isEmpty()) { 1060 | return; 1061 | } 1062 | 1063 | ResultSet resultSet = null; 1064 | try { 1065 | totalStatements++; 1066 | getLog().debug("SQL: " + sql); 1067 | 1068 | boolean ret; 1069 | int updateCountTotal = 0; 1070 | 1071 | ret = statement.execute(sql); 1072 | do { 1073 | if (!ret) { 1074 | int updateCount = statement.getUpdateCount(); 1075 | if (updateCount != -1) { 1076 | updateCountTotal += updateCount; 1077 | } 1078 | } else { 1079 | resultSet = statement.getResultSet(); 1080 | if (printResultSet) { 1081 | printResultSet(resultSet, out); 1082 | } 1083 | } 1084 | ret = statement.getMoreResults(); 1085 | } while (ret); 1086 | 1087 | getLog().debug(updateCountTotal + " rows affected"); 1088 | 1089 | if (printResultSet && showFooter) { 1090 | printResultSetCount(updateCountTotal, out); 1091 | } 1092 | 1093 | SQLWarning warning = conn.getWarnings(); 1094 | while (warning != null) { 1095 | getLog().debug(warning + " sql warning"); 1096 | warning = warning.getNextWarning(); 1097 | } 1098 | conn.clearWarnings(); 1099 | successfulStatements++; 1100 | } catch (SQLException e) { 1101 | getLog().error("Failed to execute: " + sql); 1102 | if (ON_ERROR_ABORT.equalsIgnoreCase(getOnError())) { 1103 | throw e; 1104 | } 1105 | getLog().error(e.toString()); 1106 | } finally { 1107 | if (resultSet != null) { 1108 | resultSet.close(); 1109 | } 1110 | } 1111 | } 1112 | 1113 | /** 1114 | * print any results in the result set. 1115 | * 1116 | * @param rs the resultset to print information about 1117 | * @param out the place to print results 1118 | * @throws SQLException on SQL problems. 1119 | */ 1120 | protected void printResultSet(ResultSet rs, PrintStream out) throws SQLException { 1121 | if (rs != null) { 1122 | getLog().debug("Processing new result set."); 1123 | ResultSetMetaData md = rs.getMetaData(); 1124 | int columnCount = md.getColumnCount(); 1125 | StringBuffer line = new StringBuffer(); 1126 | if (showHeaders) { 1127 | boolean first = true; 1128 | for (int col = 1; col <= columnCount; col++) { 1129 | String columnValue = md.getColumnName(col); 1130 | 1131 | if (columnValue != null) { 1132 | columnValue = columnValue.trim(); 1133 | 1134 | if (",".equals(outputDelimiter)) { 1135 | columnValue = StringEscapeUtils.escapeCsv(columnValue); 1136 | } 1137 | } 1138 | 1139 | if (first) { 1140 | first = false; 1141 | } else { 1142 | line.append(outputDelimiter); 1143 | } 1144 | line.append(columnValue); 1145 | } 1146 | out.println(line); 1147 | line = new StringBuffer(); 1148 | } 1149 | while (rs.next()) { 1150 | boolean first = true; 1151 | for (int col = 1; col <= columnCount; col++) { 1152 | String columnValue = rs.getString(col); 1153 | if (columnValue != null) { 1154 | columnValue = columnValue.trim(); 1155 | 1156 | if (",".equals(outputDelimiter)) { 1157 | columnValue = StringEscapeUtils.escapeCsv(columnValue); 1158 | } 1159 | } 1160 | 1161 | if (first) { 1162 | first = false; 1163 | } else { 1164 | line.append(outputDelimiter); 1165 | } 1166 | line.append(columnValue); 1167 | } 1168 | out.println(line); 1169 | line = new StringBuffer(); 1170 | } 1171 | } 1172 | out.println(); 1173 | } 1174 | 1175 | protected void printResultSetCount(int updateCountTotal, PrintStream out) { 1176 | out.println(updateCountTotal + " rows affected"); 1177 | } 1178 | 1179 | /** 1180 | * Contains the definition of a new transaction element. Transactions allow several files or blocks of statements to 1181 | * be executed using the same JDBC connection and commit operation in between. 1182 | */ 1183 | private class Transaction implements Comparable { 1184 | private File tSrcFile = null; 1185 | 1186 | private String tSqlCommand = ""; 1187 | 1188 | /** 1189 | * 1190 | */ 1191 | public void setSrc(File src) { 1192 | this.tSrcFile = src; 1193 | } 1194 | 1195 | /** 1196 | * 1197 | */ 1198 | public void addText(String sql) { 1199 | this.tSqlCommand += sql; 1200 | } 1201 | 1202 | /** 1203 | * 1204 | */ 1205 | private void runTransaction(PrintStream out) throws IOException, SQLException { 1206 | if (!tSqlCommand.isEmpty()) { 1207 | getLog().info("Executing commands"); 1208 | 1209 | runStatements(new StringReader(tSqlCommand), out); 1210 | } 1211 | 1212 | if (tSrcFile != null) { 1213 | getLog().info("Executing file: " + tSrcFile.getAbsolutePath()); 1214 | 1215 | Reader reader = null; 1216 | 1217 | if (StringUtils.isEmpty(encoding)) { 1218 | reader = new FileReader(tSrcFile); 1219 | } else { 1220 | reader = new InputStreamReader(Files.newInputStream(tSrcFile.toPath()), encoding); 1221 | } 1222 | 1223 | try { 1224 | runStatements(reader, out); 1225 | } finally { 1226 | reader.close(); 1227 | } 1228 | } 1229 | } 1230 | 1231 | public int compareTo(Transaction transaction) { 1232 | if (transaction.tSrcFile == null) { 1233 | if (this.tSrcFile == null) { 1234 | return 0; 1235 | } else { 1236 | return Integer.MAX_VALUE; 1237 | } 1238 | } else { 1239 | if (this.tSrcFile == null) { 1240 | return Integer.MIN_VALUE; 1241 | } else { 1242 | return this.tSrcFile.compareTo(transaction.tSrcFile); 1243 | } 1244 | } 1245 | } 1246 | } 1247 | 1248 | // 1249 | // helper accessors for unit test purposes 1250 | // 1251 | 1252 | public String getUsername() { 1253 | return this.username; 1254 | } 1255 | 1256 | public void setUsername(String username) { 1257 | this.username = username; 1258 | } 1259 | 1260 | public String getPassword() { 1261 | return this.password; 1262 | } 1263 | 1264 | public void setPassword(String password) { 1265 | this.password = password; 1266 | } 1267 | 1268 | public String getUrl() { 1269 | return this.url; 1270 | } 1271 | 1272 | public void setUrl(String url) { 1273 | this.url = url; 1274 | } 1275 | 1276 | public String getDriver() { 1277 | return this.driver; 1278 | } 1279 | 1280 | public void setDriver(String driver) { 1281 | this.driver = driver; 1282 | } 1283 | 1284 | void setAutocommit(boolean autocommit) { 1285 | this.autocommit = autocommit; 1286 | } 1287 | 1288 | public void setRollbackTransactions(boolean rollbackTransactions) { 1289 | this.rollbackTransactions = rollbackTransactions; 1290 | } 1291 | 1292 | void setFileset(Fileset fileset) { 1293 | this.fileset = fileset; 1294 | } 1295 | 1296 | public File[] getSrcFiles() { 1297 | return this.srcFiles; 1298 | } 1299 | 1300 | public void setSrcFiles(File[] files) { 1301 | this.srcFiles = files; 1302 | } 1303 | 1304 | public String getOrderFile() { 1305 | return this.orderFile; 1306 | } 1307 | 1308 | public void setOrderFile(String orderFile) { 1309 | if (FILE_SORTING_ASC.equalsIgnoreCase(orderFile)) { 1310 | this.orderFile = FILE_SORTING_ASC; 1311 | } else if (FILE_SORTING_DSC.equalsIgnoreCase(orderFile)) { 1312 | this.orderFile = FILE_SORTING_DSC; 1313 | } else { 1314 | throw new IllegalArgumentException(orderFile + " is not a valid value for orderFile, only '" 1315 | + FILE_SORTING_ASC + "' or '" + FILE_SORTING_DSC + "'."); 1316 | } 1317 | } 1318 | 1319 | /** 1320 | * Number of SQL statements executed so far that caused errors. 1321 | * 1322 | * @return the number 1323 | */ 1324 | public int getSuccessfulStatements() { 1325 | return successfulStatements; 1326 | } 1327 | 1328 | /** 1329 | * Number of SQL statements executed so far, including the ones that caused errors. 1330 | * 1331 | * @return the number 1332 | */ 1333 | public int getTotalStatements() { 1334 | return totalStatements; 1335 | } 1336 | 1337 | public String getOnError() { 1338 | return this.onError; 1339 | } 1340 | 1341 | public void setOnError(String action) { 1342 | if (ON_ERROR_ABORT.equalsIgnoreCase(action)) { 1343 | this.onError = ON_ERROR_ABORT; 1344 | } else if (ON_ERROR_CONTINUE.equalsIgnoreCase(action)) { 1345 | this.onError = ON_ERROR_CONTINUE; 1346 | } else if (ON_ERROR_ABORT_AFTER.equalsIgnoreCase(action)) { 1347 | this.onError = ON_ERROR_ABORT_AFTER; 1348 | } else { 1349 | throw new IllegalArgumentException(action + " is not a valid value for onError, only '" + ON_ERROR_ABORT 1350 | + "', '" + ON_ERROR_ABORT_AFTER + "', or '" + ON_ERROR_CONTINUE + "'."); 1351 | } 1352 | } 1353 | 1354 | /** 1355 | * Validate the database connection by executing all validation SQLs. 1356 | * 1357 | * @param conn the open database connection 1358 | * @throws java.sql.SQLException if SQL execution fails 1359 | */ 1360 | protected void validateConnection(Connection conn) throws SQLException { 1361 | if (connectionValidationSqls != null && !connectionValidationSqls.isEmpty()) { 1362 | for (String sql : connectionValidationSqls) { 1363 | if (sql != null && sql.trim().length() > 0) { 1364 | conn.createStatement().executeQuery(sql); 1365 | } 1366 | } 1367 | } 1368 | } 1369 | 1370 | /** 1371 | * Waits the time specified in connectionRetryInterval. 1372 | * 1373 | * @throws MojoExecutionException 1374 | */ 1375 | private void waitToRetryConnectionValidation() throws MojoExecutionException { 1376 | try { 1377 | Thread.sleep(this.connectionRetryInterval * 1000); 1378 | } catch (InterruptedException e) { 1379 | throw new MojoExecutionException(e.getMessage(), e); 1380 | } 1381 | } 1382 | 1383 | /** 1384 | * Closes the database connection. 1385 | */ 1386 | void closeConnection() { 1387 | if (conn != null) { 1388 | try { 1389 | conn.close(); 1390 | } catch (SQLException e) { 1391 | getLog().debug("Failed to close connection: " + e.getMessage()); 1392 | } 1393 | } 1394 | } 1395 | 1396 | /** 1397 | * Closes the database statement. 1398 | */ 1399 | private void closeStatement() { 1400 | if (statement != null) { 1401 | try { 1402 | statement.close(); 1403 | } catch (SQLException e) { 1404 | getLog().debug("Failed to close statement: " + e.getMessage()); 1405 | } 1406 | } 1407 | } 1408 | 1409 | /** 1410 | * Check is the database connection closed. 1411 | * 1412 | * @return true if the connection is closed, otherwise false 1413 | */ 1414 | protected boolean isConnectionClosed() { 1415 | try { 1416 | return conn == null || conn.isClosed(); 1417 | } catch (SQLException e) { 1418 | return false; 1419 | } 1420 | } 1421 | 1422 | protected void clear() { 1423 | sqlCommand = null; 1424 | if (transactions != null) { 1425 | transactions.clear(); 1426 | } 1427 | } 1428 | 1429 | protected int getConnectionRetryAttempts() { 1430 | return this.connectionRetryAttempts; 1431 | } 1432 | 1433 | public void setConnectionValidationSqls(List connectionValidationSql) { 1434 | this.connectionValidationSqls = connectionValidationSql; 1435 | } 1436 | 1437 | public void setConnectionRetryCount(int connectionRetryCount) { 1438 | this.connectionRetryCount = connectionRetryCount; 1439 | } 1440 | 1441 | public void setConnectionRetryInterval(int connectionRetryInterval) { 1442 | this.connectionRetryInterval = connectionRetryInterval; 1443 | } 1444 | 1445 | void setSettings(Settings settings) { 1446 | this.settings = settings; 1447 | } 1448 | 1449 | void setSettingsKey(String key) { 1450 | this.settingsKey = key; 1451 | } 1452 | 1453 | void setSkip(boolean skip) { 1454 | this.skip = skip; 1455 | } 1456 | 1457 | public void setSkipMissingFiles(boolean skipMissingFiles) { 1458 | this.skipMissingFiles = skipMissingFiles; 1459 | } 1460 | 1461 | public void setDriverProperties(String driverProperties) { 1462 | this.driverProperties = driverProperties; 1463 | } 1464 | 1465 | public String getSqlCommand() { 1466 | return sqlCommand; 1467 | } 1468 | 1469 | public void setSqlCommand(String sqlCommand) { 1470 | this.sqlCommand = sqlCommand; 1471 | } 1472 | 1473 | public List getTransactions() { 1474 | return transactions; 1475 | } 1476 | 1477 | public void setTransactions(List transactions) { 1478 | this.transactions = transactions; 1479 | } 1480 | 1481 | public void setFileFilter(MavenFileFilter filter) { 1482 | this.fileFilter = filter; 1483 | } 1484 | 1485 | public void setSecurityDispatcher(SecDispatcher securityDispatcher) { 1486 | this.securityDispatcher = securityDispatcher; 1487 | } 1488 | 1489 | public void setOutputDelimiter(String outputDelimiter) { 1490 | this.outputDelimiter = outputDelimiter; 1491 | } 1492 | 1493 | public void setOutputEncoding(String outputEncoding) { 1494 | this.outputEncoding = outputEncoding; 1495 | } 1496 | 1497 | public void setShowFooter(boolean showFooter) { 1498 | this.showFooter = showFooter; 1499 | } 1500 | } 1501 | --------------------------------------------------------------------------------