diff --git a/README.md b/README.md
index 16c4fbd..3809879 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,7 @@
# sqlcmd
-SQL command line executor using JDBC drivers. Useful for cron jobs and some automation. Porting of my previous sf.net code
+SQL command line executor using JDBC drivers. Useful for cron jobs and some automation.
+
+_Porting of my previous sf.net code_
Usage:
@@ -8,10 +10,10 @@ Usage:
FROM MY_TABLE
EOF
-Config values:
+## Config values:
-* jdbcDriverPath=Path to jdbc driver jar (loaded dynamically)
-* jdbcDriverClass=Jdbc Driver class full name
+* jdbcDriverPath=Path to jdbc driver jar (loaded dynamically) if null it must be in classpath
+* jdbcDriverClass=Jdbc Driver class full name (no need if driver registers itself)
* jdbcUrl=Jdbc connection URL
* jdbcUser=
* jdbcPass=
@@ -20,6 +22,23 @@ Config values:
* printHeader=true/false If true adds header with query's column name. Default true
* printFieldSeparator=Field separator for printing. Default tab (\t)
+## Mail config values:
+
+Mail Server:
+* mailHost=SMTP host
+* mailPort=SMTP port
+* mailAuth=true/false smtp server needs authentication?
+* mailTLS=true/false smtp server needs TLS connection?
+* mailUser=smtp auth username
+* mailPass=smtp auth password
+*
+Mail message:
+* mailFrom=Email addess in from field
+* mailSubject=Subject field
+* mailSendTo=Email addess in TO field
+
+## Config notes
+
Config values can be set also with parameters:
-p:paran_name=param_value
diff --git a/pom.xml b/pom.xml
index 53c6b76..729ff4e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,15 +6,32 @@
io.github.jdlopez
sqlcmd
- 1.0-SNAPSHOT
+ 1.1
+
+ com.sun.mail
+ javax.mail
+ 1.6.2
+
junit
junit
4.12
test
+
+ org.hsqldb
+ hsqldb
+ 2.3.2
+ test
+
+
+ com.microsoft.sqlserver
+ mssql-jdbc
+ 7.4.1.jre8
+ test
+
diff --git a/src/main/java/es/jdlopez/sqlcmd/MainRunner.java b/src/main/java/es/jdlopez/sqlcmd/MainRunner.java
index 1b48ab5..5041921 100644
--- a/src/main/java/es/jdlopez/sqlcmd/MainRunner.java
+++ b/src/main/java/es/jdlopez/sqlcmd/MainRunner.java
@@ -8,7 +8,10 @@
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
+import java.io.StringWriter;
import java.sql.Connection;
+import java.sql.Driver;
+import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
@@ -30,24 +33,55 @@ public static void main (String[] args) throws Exception {
}
String sql = readAll(in);
PrintWriter out = null;
- if (config.getOutputResult() == null)
- out = new PrintWriter(System.out);
+ StringWriter mailBody = null;
+ if (config.getMailSendTo() != null) {
+ mailBody = new StringWriter();
+ out = new PrintWriter(mailBody);
+ }
+ else if (config.getOutputResult() == null)
+ out = new PrintWriter(System.out, true);
else
out = new PrintWriter(config.getOutputResult());
Connection conn = null;
try {
- conn = DynamicDriver.getConnection(config.getJdbcDriverPath(), config.getJdbcDriverClass(),
+ if (config.getJdbcDriverPath() == null) {
+ // driver in classpath and registered
+ conn = DriverManager.getConnection(config.getJdbcUrl(), config.getJdbcUser(), config.getJdbcPass());
+ } else
+ conn = DynamicDriver.getConnection(config.getJdbcDriverPath(), config.getJdbcDriverClass(),
config.getJdbcUrl(), config.getJdbcUser(), config.getJdbcPass());
Statement st = conn.createStatement();
boolean isResultSet = st.execute(sql);
boolean hasMore = true;
+ int updateCount = st.getUpdateCount(); // just once per result
while (hasMore) {
- if (isResultSet)
+ if (isResultSet && updateCount < 0)
writeResultSet(st.getResultSet(), out, config);
else
- out.println("UpdateCount = " + st.getUpdateCount());
- hasMore = st.getMoreResults();
+ writeUpdateCount(updateCount, out, config);
+ isResultSet = st.getMoreResults();
+ updateCount = st.getUpdateCount();
+ hasMore = isResultSet || updateCount > -1;
+ }
+ // send result to mail?
+ if (config.getMailSendTo() != null && mailBody != null) {
+ SendMail sendMail;
+ if (config.getMailAuth() != null) {
+ sendMail = new SendMail(config.getMailHost(),
+ config.getMailPort(),
+ config.getMailFrom(),
+ Boolean.valueOf(config.getMailAuth()),
+ Boolean.valueOf(config.getMailTLS()),
+ config.getMailUser(),
+ config.getMailPass()
+ );
+ } else {
+ sendMail = new SendMail(config.getMailHost(),
+ config.getMailPort(),
+ config.getMailFrom());
+ }
+ sendMail.sendText(config.getMailSubject(), mailBody.toString(), config.getMailSendTo());
}
} finally {
@@ -56,16 +90,31 @@ public static void main (String[] args) throws Exception {
}
}
+ private static void writeUpdateCount(int updateCount, PrintWriter out, RunnerConfig config) {
+ String s;
+ if (config.getPrintHeader())
+ s = String.format("==================\nUpdateCount = %d\n==================", updateCount);
+ else
+ s = "UpdateCount = " + updateCount;
+ out.println(s);
+
+ }
+
private static void writeResultSet(ResultSet resultSet, PrintWriter out, RunnerConfig conf) throws SQLException {
ResultSetMetaData rsmd = resultSet.getMetaData();
int colCount = rsmd.getColumnCount();
if (conf.getPrintHeader()) {
+ StringBuffer underline = new StringBuffer();
for (int i = 1; i <= colCount; i++) {
out.print(rsmd.getColumnName(i));
- if (i < colCount)
+ underline.append(repeatChar('=', rsmd.getColumnName(i).length()));
+ if (i < colCount) {
out.print(conf.getPrintFieldSeparator());
+ underline.append(conf.getPrintFieldSeparator());
+ }
}
out.println();
+ out.println(underline.toString());
} // header
while (resultSet.next()) {
for (int i = 1; i <= colCount; i++) {
@@ -78,6 +127,10 @@ private static void writeResultSet(ResultSet resultSet, PrintWriter out, RunnerC
out.flush();
}
+ private static String repeatChar(char c, int length) {
+ return new String(new char[length]).replace('\0', c);
+ }
+
private static String readAll(InputStream in) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(in));
StringBuffer sb = new StringBuffer();
diff --git a/src/main/java/es/jdlopez/sqlcmd/RunnerConfig.java b/src/main/java/es/jdlopez/sqlcmd/RunnerConfig.java
index ebb8ef0..72d8831 100644
--- a/src/main/java/es/jdlopez/sqlcmd/RunnerConfig.java
+++ b/src/main/java/es/jdlopez/sqlcmd/RunnerConfig.java
@@ -10,6 +10,16 @@ public class RunnerConfig {
private String outputResult;
private Boolean printHeader = true;
private String printFieldSeparator = "\t";
+ // mail configuration:
+ private String mailSendTo;
+ private String mailHost;
+ private String mailPort;
+ private Boolean mailAuth;
+ private Boolean mailTLS;
+ private String mailUser;
+ private String mailPass;
+ private String mailFrom;
+ private String mailSubject;
public String getInputSQL() {
return inputSQL;
@@ -82,4 +92,76 @@ public String getPrintFieldSeparator() {
public void setPrintFieldSeparator(String printFieldSeparator) {
this.printFieldSeparator = printFieldSeparator;
}
+
+ public String getMailSendTo() {
+ return mailSendTo;
+ }
+
+ public void setMailSendTo(String mailSendTo) {
+ this.mailSendTo = mailSendTo;
+ }
+
+ public String getMailHost() {
+ return mailHost;
+ }
+
+ public void setMailHost(String mailHost) {
+ this.mailHost = mailHost;
+ }
+
+ public String getMailPort() {
+ return mailPort;
+ }
+
+ public void setMailPort(String mailPort) {
+ this.mailPort = mailPort;
+ }
+
+ public Boolean getMailAuth() {
+ return mailAuth;
+ }
+
+ public void setMailAuth(Boolean mailAuth) {
+ this.mailAuth = mailAuth;
+ }
+
+ public Boolean getMailTLS() {
+ return mailTLS;
+ }
+
+ public void setMailTLS(Boolean mailTLS) {
+ this.mailTLS = mailTLS;
+ }
+
+ public String getMailUser() {
+ return mailUser;
+ }
+
+ public void setMailUser(String mailUser) {
+ this.mailUser = mailUser;
+ }
+
+ public String getMailPass() {
+ return mailPass;
+ }
+
+ public void setMailPass(String mailPass) {
+ this.mailPass = mailPass;
+ }
+
+ public String getMailFrom() {
+ return mailFrom;
+ }
+
+ public void setMailFrom(String mailFrom) {
+ this.mailFrom = mailFrom;
+ }
+
+ public String getMailSubject() {
+ return mailSubject;
+ }
+
+ public void setMailSubject(String mailSubject) {
+ this.mailSubject = mailSubject;
+ }
}
diff --git a/src/main/java/es/jdlopez/sqlcmd/SendMail.java b/src/main/java/es/jdlopez/sqlcmd/SendMail.java
new file mode 100644
index 0000000..3afb26f
--- /dev/null
+++ b/src/main/java/es/jdlopez/sqlcmd/SendMail.java
@@ -0,0 +1,59 @@
+package es.jdlopez.sqlcmd;
+
+import javax.mail.Authenticator;
+import javax.mail.Message;
+import javax.mail.MessagingException;
+import javax.mail.PasswordAuthentication;
+import javax.mail.Session;
+import javax.mail.Transport;
+import javax.mail.internet.InternetAddress;
+import javax.mail.internet.MimeMessage;
+import java.util.Properties;
+
+public class SendMail {
+
+ private Authenticator auth;
+ private Properties sessionProps;
+ private String from;
+
+ public SendMail(String host, String port, String from) {
+ this(host, port, from, false, false, null, null);
+ }
+ public SendMail(String host, String port, String from, boolean auth, boolean tls, String user, String pass) {
+ this.from = from;
+ this.sessionProps = new Properties();
+ sessionProps.setProperty("mail.smtp.host", host);
+ sessionProps.setProperty("mail.smtp.port", port);
+ if (auth) {
+ sessionProps.setProperty("mail.smtp.auth", "true");
+ // just user pass authenticator
+ this.auth = new Authenticator() {
+ @Override
+ protected PasswordAuthentication getPasswordAuthentication() {
+ return new PasswordAuthentication(user, pass);
+ }
+ };
+ }
+ if (tls)
+ sessionProps.setProperty("mail.smtp.starttls.enable", "true");
+
+ }
+
+ public void sendText(String subject, String body, String to) throws MessagingException {
+ Session session = Session.getInstance(sessionProps, auth);
+ Message msg = new MimeMessage(session);
+
+ msg.setFrom(new InternetAddress(from));
+
+ msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(to, false));
+
+ msg.setSubject(subject);
+
+ msg.setText(body);
+ // Let's tranport sets default value
+ //msg.setHeader("X-Mailer", mailer);
+ //msg.setSentDate(new Date());
+
+ Transport.send(msg);
+ }
+}
diff --git a/src/test/java/es/jdlopez/sqlcmd/TestMain.java b/src/test/java/es/jdlopez/sqlcmd/TestMain.java
new file mode 100644
index 0000000..e66b37d
--- /dev/null
+++ b/src/test/java/es/jdlopez/sqlcmd/TestMain.java
@@ -0,0 +1,24 @@
+package es.jdlopez.sqlcmd;
+
+import org.junit.Test;
+
+import java.io.FileReader;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.util.Properties;
+
+public class TestMain {
+
+ @Test
+ public void testCreateTable() throws Exception {
+ // create table must be in previous statement: hsqldb docs
+ Properties p = new Properties();
+ p.load(new FileReader("src/test/resources/sample.properties"));
+ Connection conn = DriverManager.getConnection(p.getProperty("jdbcUrl"),
+ p.getProperty("jdbcUser"), p.getProperty("jdbcPass"));
+ conn.createStatement().executeUpdate("create table testtable1 ( field1 int, field2 varchar(10))");
+ String[] args = new String[]{"-c:src/test/resources/sample.properties", "-p:inputSQL=src/test/resources/test1.sql"};
+ MainRunner.main(args);
+ conn.createStatement().executeUpdate("drop table testtable1");
+ }
+}
diff --git a/src/test/resources/sample.properties b/src/test/resources/sample.properties
index 273eda8..6531d81 100644
--- a/src/test/resources/sample.properties
+++ b/src/test/resources/sample.properties
@@ -1,6 +1,13 @@
# database connection properties
-jdbcDriverPath=
-jdbcDriverClass=
-jdbcUrl=
-jdbcUser=
+#jdbcDriverPath=
+#jdbcDriverClass=
+jdbcUrl=jdbc:hsqldb:mem:mymemdb
+jdbcUser=SA
jdbcPass=
+
+# mail config
+mailFrom=noreply@example.com
+mailSubject=SqlCmd subject sent
+mailSendTo=nobody@example.com
+mailHost=localhost
+mailPort=25
diff --git a/src/test/resources/test1.sql b/src/test/resources/test1.sql
new file mode 100644
index 0000000..92b4a56
--- /dev/null
+++ b/src/test/resources/test1.sql
@@ -0,0 +1,15 @@
+insert into testtable1 (field1, field2)
+values
+(1, 'one'),
+(2, 'two'),
+(3, 'three'),
+(4, 'four'),
+(5, 'five');
+
+select * from testtable1;
+
+insert into testtable1 (field1, field2)
+values
+ (6, 'six')
+
+select field2, field1, 'fiexed value' as fixxedd from testtable1;