Question

I want to execute an SQL script file in Java without reading the entire file content into a big query and executing it.

Is there any other standard way?

Was it helpful?

Solution

There is no portable way of doing that. You can execute a native client as an external program to do that though:

import java.io.*;
public class CmdExec {

  public static void main(String argv[]) {
    try {
      String line;
      Process p = Runtime.getRuntime().exec
        ("psql -U username -d dbname -h serverhost -f scripfile.sql");
      BufferedReader input =
        new BufferedReader
          (new InputStreamReader(p.getInputStream()));
      while ((line = input.readLine()) != null) {
        System.out.println(line);
      }
      input.close();
    }
    catch (Exception err) {
      err.printStackTrace();
    }
  }
}
  • Code sample was extracted from here and modified to answer question assuming that the user wants to execute a PostgreSQL script file.

OTHER TIPS

There is great way of executing SQL scripts from Java without reading them yourself as long as you don't mind having a dependency on Ant. In my opinion such a dependency is very well justified in your case. Here is sample code, where SQLExec class lives in ant.jar:

private void executeSql(String sqlFilePath) {
    final class SqlExecuter extends SQLExec {
        public SqlExecuter() {
            Project project = new Project();
            project.init();
            setProject(project);
            setTaskType("sql");
            setTaskName("sql");
        }
    }

    SqlExecuter executer = new SqlExecuter();
    executer.setSrc(new File(sqlFilePath));
    executer.setDriver(args.getDriver());
    executer.setPassword(args.getPwd());
    executer.setUserid(args.getUser());
    executer.setUrl(args.getUrl());
    executer.execute();
}

Flyway library is really good for this:

    Flyway flyway = new Flyway();
    flyway.setDataSource(dbConfig.getUrl(), dbConfig.getUsername(), dbConfig.getPassword());
    flyway.setLocations("classpath:db/scripts");
    flyway.clean();
    flyway.migrate();

This scans the locations for scripts and runs them in order. Scripts can be versioned with V01__name.sql so if just the migrate is called then only those not already run will be run. Uses a table called 'schema_version' to keep track of things. But can do other things too, see the docs: flyway.

The clean call isn't required, but useful to start from a clean DB. Also, be aware of the location (default is "classpath:db/migration"), there is no space after the ':', that one caught me out.

No, you must read the file, split it into separate queries and then execute them individually (or using the batch API of JDBC).

One of the reasons is that every database defines their own way to separate SQL statements (some use ;, others /, some allow both or even to define your own separator).

You cannot do using JDBC as it does not support . Work around would be including iBatis iBATIS is a persistence framework and call the Scriptrunner constructor as shown in iBatis documentation .

Its not good to include a heavy weight persistence framework like ibatis in order to run a simple sql scripts any ways which you can do using command line

$ mysql -u root -p db_name < test.sql

Since JDBC doesn't support this option the best way to solve this question is executing command lines via the Java Program. Bellow is an example to postgresql:

private void executeSqlFile() {
     try {
         Runtime rt = Runtime.getRuntime();
         String executeSqlCommand = "psql -U (user) -h (domain) -f (script_name) (dbName)";
         Process pr = rt.exec();
         int exitVal = pr.waitFor();
         System.out.println("Exited with error code " + exitVal);
      } catch (Exception e) {
        System.out.println(e.toString());
      }
}

The simplest external tool that I found that is also portable is jisql - https://www.xigole.com/software/jisql/jisql.jsp . You would run it as:

java -classpath lib/jisql.jar:\
          lib/jopt-simple-3.2.jar:\
          lib/javacsv.jar:\
           /home/scott/postgresql/postgresql-8.4-701.jdbc4.jar 
    com.xigole.util.sql.Jisql -user scott -password blah     \
    -driver postgresql                                       \
    -cstring jdbc:postgresql://localhost:5432/scott -c \;    \
    -query "select * from test;"

JDBC does not support this option (although a specific DB driver may offer this). Anyway, there should not be a problem with loading all file contents into memory.

Try this code:

String strProc =
         "DECLARE \n" +
         "   sys_date DATE;"+
         "" +
         "BEGIN\n" +
         "" +
         "   SELECT SYSDATE INTO sys_date FROM dual;\n" +
         "" +
         "END;\n";

try{
    DriverManager.registerDriver ( new oracle.jdbc.driver.OracleDriver () );
    Connection connection = DriverManager.getConnection ("jdbc:oracle:thin:@your_db_IP:1521:your_db_SID","user","password");  
    PreparedStatement psProcToexecute = connection.prepareStatement(strProc);
    psProcToexecute.execute();
}catch (Exception e) {
    System.out.println(e.toString());  
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top