Browse Source

<sql> would parse source files before telling you that you forgot to

specify a JDBC driver - make it fail faster.

<sql> didn't reset its state (7552)

<sql> wouldn't close input files if an error occured.

I've left two XXX comments in the source for people who may know
better than me.


git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@272401 13f79535-47bb-0310-9956-ffa450edef68
master
Stefan Bodewig 23 years ago
parent
commit
f152ff3665
1 changed files with 223 additions and 177 deletions
  1. +223
    -177
      src/main/org/apache/tools/ant/taskdefs/SQLExec.java

+ 223
- 177
src/main/org/apache/tools/ant/taskdefs/SQLExec.java View File

@@ -100,6 +100,8 @@ import java.sql.ResultSetMetaData;
* @author <A href="mailto:gholam@xtra.co.nz">Michael McCallum</A>
* @author <A href="mailto:tim.stephenson@sybase.com">Tim Stephenson</A>
*
* @since Ant 1.2
*
* @ant.task name="sql" category="database"
*/
public class SQLExec extends Task {
@@ -119,6 +121,7 @@ public class SQLExec extends Task {
*/
private static Hashtable loaderMap = new Hashtable(3);

// XXX - why is this public?
public boolean caching = true;

private int goodSql = 0;
@@ -351,10 +354,12 @@ public class SQLExec extends Task {
}

/**
* Set the Delimiter type for this sql task. The delimiter type takes
* two values - normal and row. Normal means that any occurence of the delimiter
* terminate the SQL command whereas with row, only a line containing just the
* delimiter is recognized as the end of the command.
* Set the Delimiter type for this sql task.
*
* <p>The delimiter type takes two values - normal and row. Normal
* means that any occurence of the delimiter terminate the SQL
* command whereas with row, only a line containing just the
* delimiter is recognized as the end of the command.</p>
*/
public void setDelimiterType(DelimiterType delimiterType) {
this.delimiterType = delimiterType.getValue();
@@ -384,7 +389,7 @@ public class SQLExec extends Task {
/**
* Shall we append to an existing file?
*
* @since 1.36, Ant 1.5
* @since Ant 1.5
*/
public void setAppend(boolean append) {
this.append = append;
@@ -415,214 +420,245 @@ public class SQLExec extends Task {
* Load the sql file and then execute it
*/
public void execute() throws BuildException {
Vector savedTransaction = (Vector) transactions.clone();
String savedSqlCommand = sqlCommand;

sqlCommand = sqlCommand.trim();

if (srcFile == null && sqlCommand.length()==0 && filesets.isEmpty()) {
if (transactions.size() == 0) {
throw new BuildException("Source file or fileset, transactions or sql statement must be set!", location);
try {
if (srcFile == null && sqlCommand.length()==0
&& filesets.isEmpty()) {
if (transactions.size() == 0) {
throw new BuildException("Source file or fileset, "
+ "transactions or sql statement "
+ "must be set!", location);
}
}
if (driver == null) {
throw new BuildException("Driver attribute must be set!",
location);
}
} else {
if (userId == null) {
throw new BuildException("User Id attribute must be set!",
location);
}
if (password == null) {
throw new BuildException("Password attribute must be set!",
location);
}
if (url == null) {
throw new BuildException("Url attribute must be set!",
location);
}
if (srcFile != null && !srcFile.exists()) {
throw new BuildException("Source file does not exist!",
location);
}
Driver driverInstance = null;
try {
Class dc;
if (classpath != null) {
// check first that it is not already loaded otherwise
// consecutive runs seems to end into an OutOfMemoryError
// or it fails when there is a native library to load
// several times.
// this is far from being perfect but should work
// in most cases.
synchronized (loaderMap){
if (caching){
loader = (AntClassLoader)loaderMap.get(driver);
}
if (loader == null){
log( "Loading " + driver
+ " using AntClassLoader with classpath "
+ classpath,
Project.MSG_VERBOSE );
loader = new AntClassLoader(project, classpath);
if (caching){
loaderMap.put(driver, loader);
}
} else {
log("Loading " + driver
+ " using a cached AntClassLoader.",
Project.MSG_VERBOSE);
}
}
dc = loader.loadClass(driver);
}
else {
log("Loading " + driver + " using system loader.",
Project.MSG_VERBOSE);
dc = Class.forName(driver);
}
driverInstance = (Driver) dc.newInstance();
}catch(ClassNotFoundException e){
throw new BuildException("Class Not Found: JDBC driver "
+ driver + " could not be loaded",
location);
}catch(IllegalAccessException e){
throw new BuildException("Illegal Access: JDBC driver "
+ driver + " could not be loaded",
location);
}catch(InstantiationException e) {
throw new BuildException("Instantiation Exception: JDBC driver "
+ driver + " could not be loaded",
location);
}

// deal with the filesets
for (int i=0; i<filesets.size(); i++) {
FileSet fs = (FileSet) filesets.elementAt(i);
DirectoryScanner ds = fs.getDirectoryScanner(project);
File srcDir = fs.getDir(project);

String[] srcFiles = ds.getIncludedFiles();

// Make a transaction for each file
for ( int j=0 ; j<srcFiles.length ; j++ ) {
Transaction t = createTransaction();
t.setSrc(new File(srcDir, srcFiles[j]));
}
}

// Make a transaction group for the outer command
Transaction t = createTransaction();
t.setSrc(srcFile);
t.addText(sqlCommand);
}

if (driver == null) {
throw new BuildException("Driver attribute must be set!", location);
}
if (userId == null) {
throw new BuildException("User Id attribute must be set!", location);
}
if (password == null) {
throw new BuildException("Password attribute must be set!", location);
}
if (url == null) {
throw new BuildException("Url attribute must be set!", location);
}
if (srcFile != null && !srcFile.exists()) {
throw new BuildException("Source file does not exist!", location);
}
Driver driverInstance = null;
try {
Class dc;
if (classpath != null) {
// check first that it is not already loaded otherwise
// consecutive runs seems to end into an OutOfMemoryError
// or it fails when there is a native library to load
// several times.
// this is far from being perfect but should work in most cases.
synchronized (loaderMap){
if (caching){
loader = (AntClassLoader)loaderMap.get(driver);
}
if (loader == null){
log( "Loading " + driver + " using AntClassLoader with classpath " + classpath,
Project.MSG_VERBOSE );
loader = new AntClassLoader(project, classpath);
if (caching){
loaderMap.put(driver, loader);
}
} else {
log("Loading " + driver + " using a cached AntClassLoader.",
Project.MSG_VERBOSE);
}
try{
log("connecting to " + url, Project.MSG_VERBOSE );
Properties info = new Properties();
info.put("user", userId);
info.put("password", password);
conn = driverInstance.connect(url, info);
if (conn == null) {
// Driver doesn't understand the URL
throw new SQLException("No suitable Driver for "+url);
}
if (!isValidRdbms(conn)) {
return;
}
dc = loader.loadClass(driver);
}
else {
log("Loading " + driver + " using system loader.", Project.MSG_VERBOSE);
dc = Class.forName(driver);
}
driverInstance = (Driver) dc.newInstance();
}catch(ClassNotFoundException e){
throw new BuildException("Class Not Found: JDBC driver " + driver + " could not be loaded", location);
}catch(IllegalAccessException e){
throw new BuildException("Illegal Access: JDBC driver " + driver + " could not be loaded", location);
}catch(InstantiationException e) {
throw new BuildException("Instantiation Exception: JDBC driver " + driver + " could not be loaded", location);
}

try{
log("connecting to " + url, Project.MSG_VERBOSE );
Properties info = new Properties();
info.put("user", userId);
info.put("password", password);
conn = driverInstance.connect(url, info);

if (conn == null) {
// Driver doesn't understand the URL
throw new SQLException("No suitable Driver for "+url);
}

if (!isValidRdbms(conn)) {
return;
}

conn.setAutoCommit(autocommit);
conn.setAutoCommit(autocommit);

statement = conn.createStatement();
statement = conn.createStatement();

PrintStream out = System.out;
try {
if (output != null) {
log("Opening PrintStream to output file " + output, Project.MSG_VERBOSE);
out = new PrintStream(new BufferedOutputStream(new FileOutputStream(output.getAbsolutePath(), append)));
}
// Process all transactions
for (Enumeration e = transactions.elements();
e.hasMoreElements();) {
PrintStream out = System.out;
try {
if (output != null) {
log("Opening PrintStream to output file " + output,
Project.MSG_VERBOSE);
out = new PrintStream(
new BufferedOutputStream(
new FileOutputStream(output
.getAbsolutePath(),
append)));
}
// Process all transactions
for (Enumeration e = transactions.elements();
e.hasMoreElements();) {
((Transaction) e.nextElement()).runTransaction(out);
if (!autocommit) {
log("Commiting transaction", Project.MSG_VERBOSE);
conn.commit();
((Transaction) e.nextElement()).runTransaction(out);
if (!autocommit) {
log("Commiting transaction", Project.MSG_VERBOSE);
conn.commit();
}
}
}
}
finally {
if (out != null && out != System.out) {
out.close();
finally {
if (out != null && out != System.out) {
out.close();
}
}
} catch(IOException e){
if (!autocommit && conn != null && onError.equals("abort")) {
try {
conn.rollback();
} catch (SQLException ex) {}
}
throw new BuildException(e, location);
} catch(SQLException e){
if (!autocommit && conn != null && onError.equals("abort")) {
try {
conn.rollback();
} catch (SQLException ex) {}
}
throw new BuildException(e, location);
}
} catch(IOException e){
if (!autocommit && conn != null && onError.equals("abort")) {
try {
conn.rollback();
} catch (SQLException ex) {}
}
throw new BuildException(e, location);
} catch(SQLException e){
if (!autocommit && conn != null && onError.equals("abort")) {
finally {
try {
conn.rollback();
} catch (SQLException ex) {}
}
throw new BuildException(e, location);
}
finally {
try {
if (statement != null) {
statement.close();
}
if (conn != null) {
conn.close();
if (statement != null) {
statement.close();
}
if (conn != null) {
conn.close();
}
}
catch (SQLException e) {}
}
catch (SQLException e) {}
log(goodSql + " of " + totalSql +
" SQL statements executed successfully");
} finally {
transactions = savedTransaction;
sqlCommand = savedSqlCommand;
}
log(goodSql + " of " + totalSql +
" SQL statements executed successfully");
}

protected void runStatements(Reader reader, PrintStream out) throws SQLException, IOException {
protected void runStatements(Reader reader, PrintStream out)
throws SQLException, IOException {
String sql = "";
String line = "";
BufferedReader in = new BufferedReader(reader);
try{
while ((line=in.readLine()) != null){
line = line.trim();
line = project.replaceProperties(line);
if (line.startsWith("//")) {
continue;
}
if (line.startsWith("--")) {
continue;
}
StringTokenizer st = new StringTokenizer(line);
if (st.hasMoreTokens()) {
String token = st.nextToken();
if ("REM".equalsIgnoreCase(token)) {
continue;
}
}

sql += " " + line;
sql = sql.trim();

// SQL defines "--" as a comment to EOL
// and in Oracle it may contain a hint
// so we cannot just remove it, instead we must end it
if (line.indexOf("--") >= 0) {
sql += "\n";
}

if (delimiterType.equals(DelimiterType.NORMAL) && sql.endsWith(delimiter) ||
delimiterType.equals(DelimiterType.ROW) && line.equals(delimiter)) {
log("SQL: " + sql, Project.MSG_VERBOSE);
execSQL(sql.substring(0, sql.length() - delimiter.length()), out);
sql = "";
while ((line=in.readLine()) != null){
line = line.trim();
line = project.replaceProperties(line);
if (line.startsWith("//")) {
continue;
}
if (line.startsWith("--")) {
continue;
}
StringTokenizer st = new StringTokenizer(line);
if (st.hasMoreTokens()) {
String token = st.nextToken();
if ("REM".equalsIgnoreCase(token)) {
continue;
}
}
// Catch any statements not followed by ;
if(!sql.equals("")){
execSQL(sql, out);
sql += " " + line;
sql = sql.trim();
// SQL defines "--" as a comment to EOL
// and in Oracle it may contain a hint
// so we cannot just remove it, instead we must end it
if (line.indexOf("--") >= 0) {
sql += "\n";
}
if ((delimiterType.equals(DelimiterType.NORMAL)
&& sql.endsWith(delimiter))
||
(delimiterType.equals(DelimiterType.ROW)
&& line.equals(delimiter))) {
log("SQL: " + sql, Project.MSG_VERBOSE);
execSQL(sql.substring(0, sql.length() - delimiter.length()),
out);
sql = "";
}
}catch(SQLException e){
throw e;
}

// Catch any statements not followed by ;
if(!sql.equals("")){
execSQL(sql, out);
}
}
/**
@@ -647,13 +683,16 @@ public class SQLExec extends Task {
}
if (version != null) {
String theVersion = dmd.getDatabaseProductVersion().toLowerCase();
// XXX maybe better toLowerCase(Locale.US)
String theVersion =
dmd.getDatabaseProductVersion().toLowerCase();
log("Version = " + theVersion, Project.MSG_VERBOSE);
if (theVersion == null ||
!(theVersion.startsWith(version) ||
theVersion.indexOf(" " + version) >= 0)) {
log("Not the required version: \""+ version +"\"", Project.MSG_VERBOSE);
log("Not the required version: \""
+ version +"\"", Project.MSG_VERBOSE);
return false;
}
}
@@ -673,7 +712,7 @@ public class SQLExec extends Task {
protected void execSQL(String sql, PrintStream out) throws SQLException {
// Check and ignore empty statements
if ("".equals(sql.trim())) {
return;
return;
}
try {
@@ -699,7 +738,7 @@ public class SQLExec extends Task {
catch (SQLException e) {
log("Failed to execute: " + sql, Project.MSG_ERR);
if (!onError.equals("continue")) {
throw e;
throw e;
}
log(e.toString(), Project.MSG_ERR);
}
@@ -779,7 +818,8 @@ public class SQLExec extends Task {
this.tSqlCommand += sql;
}

private void runTransaction(PrintStream out) throws IOException, SQLException {
private void runTransaction(PrintStream out)
throws IOException, SQLException {
if (tSqlCommand.length() != 0) {
log("Executing commands", Project.MSG_INFO);
runStatements(new StringReader(tSqlCommand), out);
@@ -788,10 +828,16 @@ public class SQLExec extends Task {
if (tSrcFile != null) {
log("Executing file: " + tSrcFile.getAbsolutePath(),
Project.MSG_INFO);
Reader reader = (encoding == null) ? new FileReader(tSrcFile)
: new InputStreamReader(new FileInputStream(tSrcFile), encoding);
runStatements(reader, out);
reader.close();
Reader reader =
(encoding == null) ? new FileReader(tSrcFile)
: new InputStreamReader(
new FileInputStream(tSrcFile),
encoding);
try {
runStatements(reader, out);
} finally {
reader.close();
}
}
}
}


Loading…
Cancel
Save