You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ranger.apache.org by ma...@apache.org on 2015/01/28 18:03:53 UTC
[2/3] incubator-ranger git commit: RANGER-226: Support JDBC based SQL
invocation - adding jisql
RANGER-226: Support JDBC based SQL invocation - adding jisql
Signed-off-by: sneethiraj <sn...@apache.org>
Project: http://git-wip-us.apache.org/repos/asf/incubator-ranger/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-ranger/commit/6781cc9c
Tree: http://git-wip-us.apache.org/repos/asf/incubator-ranger/tree/6781cc9c
Diff: http://git-wip-us.apache.org/repos/asf/incubator-ranger/diff/6781cc9c
Branch: refs/heads/stack
Commit: 6781cc9c4593b22cc3b497f46b7be8ec7bfaabd6
Parents: 78cc53a
Author: vperiasamy <vp...@hortonworks.com>
Authored: Tue Jan 27 19:16:21 2015 -0500
Committer: sneethiraj <sn...@apache.org>
Committed: Tue Jan 27 21:32:12 2015 -0500
----------------------------------------------------------------------
jisql/pom.xml | 43 ++
.../util/outputformatter/CSVFormatter.java | 160 ++++
.../util/outputformatter/DefaultFormatter.java | 353 +++++++++
.../util/outputformatter/JisqlFormatter.java | 96 +++
.../util/outputformatter/XMLFormatter.java | 129 ++++
.../main/java/org/apache/util/sql/Jisql.java | 734 +++++++++++++++++++
.../java/org/apache/util/sql/MaskingThread.java | 71 ++
.../java/org/apache/util/sql/MySQLPLRunner.java | 345 +++++++++
pom.xml | 1 +
src/main/assembly/admin-web.xml | 23 +-
10 files changed, 1954 insertions(+), 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/6781cc9c/jisql/pom.xml
----------------------------------------------------------------------
diff --git a/jisql/pom.xml b/jisql/pom.xml
new file mode 100644
index 0000000..6d955d7
--- /dev/null
+++ b/jisql/pom.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>jisql</artifactId>
+ <version>0.1.0</version>
+ <name>Jdbc SQL Connector</name>
+ <description>Jdbc SQL Connector to execute sql statement in any db</description>
+ <packaging>jar</packaging>
+ <parent>
+ <groupId>org.apache.ranger</groupId>
+ <artifactId>ranger</artifactId>
+ <version>0.4.0</version>
+ <relativePath>..</relativePath>
+ </parent>
+ <dependencies>
+ <dependency>
+ <groupId>net.sourceforge.javacsv</groupId>
+ <artifactId>javacsv</artifactId>
+ <version>2.0</version>
+ </dependency>
+ <dependency>
+ <groupId>net.sf.jopt-simple</groupId>
+ <artifactId>jopt-simple</artifactId>
+ <version>3.2</version>
+ </dependency>
+ </dependencies>
+</project>
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/6781cc9c/jisql/src/main/java/org/apache/util/outputformatter/CSVFormatter.java
----------------------------------------------------------------------
diff --git a/jisql/src/main/java/org/apache/util/outputformatter/CSVFormatter.java b/jisql/src/main/java/org/apache/util/outputformatter/CSVFormatter.java
new file mode 100644
index 0000000..6e80b42
--- /dev/null
+++ b/jisql/src/main/java/org/apache/util/outputformatter/CSVFormatter.java
@@ -0,0 +1,160 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.util.outputformatter;
+
+import java.io.PrintStream;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+
+import java.nio.charset.Charset;
+
+import joptsimple.OptionParser;
+import joptsimple.OptionSet;
+
+import com.csvreader.CsvWriter;
+
+
+/**
+ * This is the default formatter for Jisql. It outputs data in a "normal"
+ * format that is similar to most other database command line formatters.
+ *
+ */
+public class CSVFormatter implements JisqlFormatter {
+ private char delimiter = ',';
+ private boolean includeColumnNames = false;
+
+
+ /**
+ * Sets a the supported option list for this formatter. This formatter accepts
+ * the following options:
+ *
+ * <p> </p>
+ *
+ * <ul>
+ * <li><<b>delimiter</b> specifies the delimiter to use. By default a comma is
+ * used</li>
+ * <li><b>colnames</b> if included then column names are printed as the first
+ * line of output. By default they are not included</li>
+ * </ul>
+ *
+ * @param parser the OptionParser to use.
+ *
+ */
+ public void setSupportedOptions( OptionParser parser ) {
+ parser.accepts( "delimiter" ).withRequiredArg().ofType( String.class );
+ parser.accepts( "colnames" );
+ }
+
+ /**
+ * Consumes any options that were specified on the command line.
+ *
+ * @param options the OptionSet that the main driver is using.
+ *
+ * @throws Exception if there is a problem parsing the command line arguments.
+ *
+ */
+ public void consumeOptions( OptionSet options ) throws Exception {
+ if( options.has( "delimiter" ) )
+ delimiter = ((String)(options.valueOf( "delimiter" ))).charAt( 0 );
+
+ if( options.has( "colnames" ) )
+ includeColumnNames = true;
+ }
+
+ /**
+ * Called to output a usage message to the command line window. This
+ * message should contain information on how to call the formatter.
+ *
+ * @param out the PrintStream to display the usage message on.
+ *
+ */
+ public void usage( PrintStream out ) {
+ out.println("\t-delimiter specifies the character to use as the delimiter. This defaults to \"" + delimiter + "\"" );
+ out.println("\t-colnames outputs column names. By default there are no column names." );
+ }
+
+ /**
+ * Outputs an optional header for the CSV data. This header is only enabled
+ * if the "colnames" parameter is included.
+ *
+ * @param out a PrintStream to send any output to.
+ * @param metaData the ResultSetMetaData for the output.
+ *
+ */
+ public void formatHeader( PrintStream out, ResultSetMetaData metaData ) throws Exception {
+ if( includeColumnNames ) {
+ int numColumns = metaData.getColumnCount();
+
+ //
+ // output the column names
+ //
+ for (int i = 1; i <= numColumns; i++) {
+ out.print( metaData.getColumnName(i).trim() );
+ if( (i + 1) <= numColumns )
+ out.print( delimiter );
+ }
+
+ out.println();
+ }
+ }
+
+
+ /**
+ * Called to output the data. This class uses a third party library to output
+ * the CSV data. The library escapes the data as needed.
+ *
+ * @param out the PrintStream to output data to.
+ * @param resultSet the ResultSet for the row.
+ * @param metaData the ResultSetMetaData for the row.
+ *
+ *
+ */
+ public void formatData( PrintStream out, ResultSet resultSet, ResultSetMetaData metaData ) throws Exception {
+
+ CsvWriter csvWriter = new CsvWriter( out, delimiter, Charset.forName( "us-ascii" ) );
+
+ while( resultSet.next() ) {
+ int numColumns = metaData.getColumnCount();
+
+ for (int i = 1; i <= numColumns; i++) {
+ String result = resultSet.getString(i);
+ if( !resultSet.wasNull() )
+ csvWriter.write( result );
+ else
+ csvWriter.write( "" );
+ }
+
+ csvWriter.endRecord();
+ }
+
+ csvWriter.flush();
+ }
+
+
+ /**
+ * Outputs a footer for a query. For the CSVFormatter this method does nothing.
+ *
+ * @param out the PrintStream to output data to.
+ * @param metaData the ResultSetMetaData for the output.
+ *
+ */
+ public void formatFooter( PrintStream out, ResultSetMetaData metaData ) throws Exception {
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/6781cc9c/jisql/src/main/java/org/apache/util/outputformatter/DefaultFormatter.java
----------------------------------------------------------------------
diff --git a/jisql/src/main/java/org/apache/util/outputformatter/DefaultFormatter.java b/jisql/src/main/java/org/apache/util/outputformatter/DefaultFormatter.java
new file mode 100644
index 0000000..a9fac4d
--- /dev/null
+++ b/jisql/src/main/java/org/apache/util/outputformatter/DefaultFormatter.java
@@ -0,0 +1,353 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.util.outputformatter;
+
+import java.io.PrintStream;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+
+import joptsimple.OptionParser;
+import joptsimple.OptionSet;
+
+
+/**
+ * This is the default formatter for Jisql. It outputs data in a "normal"
+ * format that is similar to most other database command line formatters.
+ *
+ */
+public class DefaultFormatter implements JisqlFormatter {
+ private boolean trimColumns = false;
+ private int columnWidth = 2048; // can be overridden with the -w switch
+ private char spacer = ' ';
+ private boolean printNull = true;
+ private boolean leftJustify = false;
+ private boolean printHeader = true;
+ private boolean debug = false;
+ private String delimiter = " | ";
+
+
+ /**
+ * Sets a the option list for this formatter. This formatter accepts the
+ * following options:
+ *
+ * <li><b>-noheader</b> do not print the header column info.</li>
+ * <li><b>-spacer</b> The character to use for "empty" space. This
+ * defaults to the space character. From mrider - "I added the ability to
+ * specify the spacer for columns - which used to be the single char ' '. I did
+ * this because of brain-dead Windows' command line copy/paste. It seems that when
+ * a line of text ends in space, copy does not copy that space. Which makes it
+ * difficult to copy/paste into another program. This can probably be ignored
+ * most of the time."</li>
+ * <li><b>-delimiter</b> Specify a single character delimiter for columns.</li>
+ * <li><b>-trim</b> trim the spaces from columns.</li>
+ * <li><b>-nonull</b> print an empty string instead of the word "NULL"
+ * when there is a null value.<li>
+ * <li><b>-left</b> left justify the output</li>
+ * <li><b>-w</b> specify the max width of a column. The default is 2048</li>
+ * <li><b>-debug</b> add debug headers to the output</li>
+ * </ul>
+ *
+ * @param parser the OptionParser to use.
+ *
+ */
+ public void setSupportedOptions( OptionParser parser ) {
+ parser.accepts( "trim" );
+ parser.accepts( "w" ).withRequiredArg().ofType( Integer.class );
+ parser.accepts( "spacer" ).withRequiredArg().ofType( String.class );
+ parser.accepts( "left" );
+ parser.accepts( "nonull" );
+ parser.accepts( "noheader" );
+ parser.accepts( "debug" );
+ parser.accepts( "delimiter" ).withRequiredArg().ofType( String.class );
+ }
+
+ /**
+ * Consumes any options that were specified on the command line.
+ *
+ * @param options the OptionSet that the main driver is using.
+ *
+ * @throws Exception if there is a problem parsing the command line arguments.
+ *
+ */
+ public void consumeOptions( OptionSet options ) throws Exception {
+
+ if( options.has( "trim" ) )
+ trimColumns = true;
+
+ if( options.has( "w" ) )
+ columnWidth = (Integer)options.valueOf( "w" );
+
+ if( options.has( "spacer" ) )
+ spacer = ((String)(options.valueOf( "spacer" ))).charAt( 0 );
+
+ if( options.has( "left" ) )
+ leftJustify = true;
+
+ if( options.has( "nonull" ) )
+ printNull = false;
+
+ if( options.has( "noheader" ) )
+ printHeader = false;
+
+ if( options.has( "debug" ) )
+ debug = true;
+
+ if( options.hasArgument( "delimiter" ) )
+ delimiter = (String)options.valueOf( "delimiter" );
+ }
+
+
+
+ /**
+ * Called to output a usage message to the command line window. This
+ * message should contain information on how to call the formatter.
+ *
+ * @param out the stream to print the output on
+ *
+ */
+ public void usage( PrintStream out ) {
+ out.println("\t-w specifies the maximum field width for a column. The default is to output the full width of the column");
+ out.println("\t-spacer changes the spacer between columns from a single space to the first character of the argument");
+ out.println("\t-noheader do not print any header columns");
+ out.println("\t-left left justify the output");
+ out.println("\t-trim trim the data output. This is useful when specifying a delimiter.");
+ out.println("\t-nonull print the empty string instead of the word \"NULL\" for null values.");
+ out.println("\t-debug shows extra information about the output." );
+ out.println("\t-delimiter specifies the delimiter. The default is \"" + delimiter + "\"." );
+
+ }
+
+ /**
+ * Outputs a header for a query. For the DefaultFormatter the data is output
+ * by default unless the "noheader" option is specified.
+ *
+ * @param out - a PrintStream to send any output to.
+ * @param metaData - the ResultSetMetaData for the output.
+ *
+ */
+ public void formatHeader( PrintStream out, ResultSetMetaData metaData ) throws Exception {
+ if( printHeader ) {
+ int numColumns = metaData.getColumnCount();
+
+ if( debug ) {
+ for (int i = 1; i <= numColumns; i++) {
+ out.print( formatLabel( metaData.getColumnTypeName(i),
+ metaData.getColumnDisplaySize(i)));
+ out.print(delimiter);
+ }
+ }
+ //
+ // output the column names
+ //
+ for (int i = 1; i <= numColumns; i++) {
+ out.print( formatLabel( metaData.getColumnName(i),
+ metaData.getColumnDisplaySize(i)));
+ out.print(delimiter);
+ }
+
+ out.println();
+
+ //
+ // output pretty dividers
+ //
+ for (int i = 1; i <= numColumns; i++) {
+ out.print( formatSeparator( metaData.getColumnName(i),
+ metaData.getColumnDisplaySize(i)));
+
+ if (i == numColumns)
+ out.print("-|");
+ else
+ out.print("-+-");
+ }
+
+ out.println();
+ }
+ }
+
+
+ /**
+ * Called to output the data.
+ *
+ * @param out the PrintStream to output data to.
+ * @param resultSet the ResultSet for the row.
+ * @param metaData the ResultSetMetaData for the row.
+ *
+ *
+ */
+ public void formatData( PrintStream out, ResultSet resultSet, ResultSetMetaData metaData ) throws Exception {
+
+ while( resultSet.next() ) {
+ int numColumns = metaData.getColumnCount();
+
+ for (int i = 1; i <= numColumns; i++) {
+ out.print( formatValue( metaData.getColumnName(i),
+ resultSet.getString(i),
+ metaData.getColumnDisplaySize(i)));
+ out.print( delimiter );
+ }
+
+ out.println();
+ }
+ }
+
+
+ /**
+ * Outputs a footer for a query. This is called after all data has been
+ * exhausted. This method isn't used in the DefaultFormatter.
+ *
+ * @param out the PrintStream to output data to.
+ * @param metaData the ResultSetMetaData for the output.
+ *
+ */
+ public void formatFooter( PrintStream out, ResultSetMetaData metaData ) throws Exception {
+ }
+
+
+
+ /**
+ * Formats a label for output.
+ *
+ * @param s - the label to format
+ * @param width - the width of the field
+ *
+ * @return the formated label
+ *
+ */
+ private String formatLabel(String s, int width) {
+ if (s == null)
+ s = "NULL";
+
+ if (columnWidth != 0) {
+ if (width > columnWidth)
+ width = columnWidth;
+ }
+
+ if (width < s.length())
+ width = s.length();
+
+ int len = s.length();
+
+ if (len >= width)
+ return s.substring(0, width);
+
+ int fillWidth = width - len;
+ StringBuffer fill = new StringBuffer(fillWidth);
+ for (int i = 0; i < fillWidth; ++i)
+ fill.append(spacer);
+ if (leftJustify)
+ return s + fill;
+ else if (s.startsWith("-"))
+ return "-" + fill + s.substring(1);
+ else
+ return fill + s;
+ }
+
+ /**
+ * Formats a separator for display.
+ *
+ * @param s - the field for which the separator is being generated
+ * @param width - the width of the field
+ *
+ * @return the formated separator
+ *
+ */
+ private String formatSeparator(String s, int width) {
+ s = "NULL";
+
+ if (columnWidth != 0) {
+ if (width > columnWidth)
+ width = columnWidth;
+ }
+
+ if (width < s.length())
+ width = s.length();
+
+ int len = s.length();
+
+ if (len >= width)
+ width = len;
+
+ StringBuffer fill = new StringBuffer(width);
+ for (int i = 0; i < width; ++i)
+ fill.append('-');
+
+ if( trimColumns )
+ return fill.toString().trim();
+ else
+ return fill.toString();
+ }
+
+ /**
+ * Formats a value for display.
+ *
+ * @param label the label associated with the value (for width purposes)
+ * @param s - the value to format
+ * @param width - the width of the field from the db.
+ *
+ * @return the formatted field.
+ *
+ */
+ private String formatValue(String label, String s, int width) {
+ if (s == null) {
+ if( printNull )
+ s = "NULL";
+ else
+ s = "";
+ }
+
+ if (columnWidth != 0) {
+ if (width > columnWidth)
+ width = columnWidth;
+ }
+
+ if (width < label.length())
+ width = label.length();
+
+ int len = s.length();
+
+ if (len >= width) {
+ if( trimColumns )
+ return s.substring(0, width).trim();
+ else
+ return s.substring(0, width);
+ }
+
+ int fillWidth = width - len;
+ StringBuffer fill = new StringBuffer(fillWidth);
+ for (int i = 0; i < fillWidth; ++i)
+ fill.append(spacer);
+
+ StringBuilder returnValue = new StringBuilder();
+
+ if (leftJustify)
+ returnValue.append( s + fill );
+ else if (s.startsWith("-"))
+ returnValue.append( "-" + fill + s.substring(1) );
+ else {
+ returnValue.append( fill + s );
+ }
+
+ if( trimColumns ) {
+ return returnValue.toString().trim();
+ }
+ else {
+ return returnValue.toString();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/6781cc9c/jisql/src/main/java/org/apache/util/outputformatter/JisqlFormatter.java
----------------------------------------------------------------------
diff --git a/jisql/src/main/java/org/apache/util/outputformatter/JisqlFormatter.java b/jisql/src/main/java/org/apache/util/outputformatter/JisqlFormatter.java
new file mode 100644
index 0000000..838225b
--- /dev/null
+++ b/jisql/src/main/java/org/apache/util/outputformatter/JisqlFormatter.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.util.outputformatter;
+
+import java.io.PrintStream;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+
+import joptsimple.OptionParser;
+import joptsimple.OptionSet;
+
+
+/**
+ * This is the definition of what a JisqlFormatter does.
+ *
+ */
+public interface JisqlFormatter {
+
+ /**
+ * Sets a the option list for this formatter.
+ *
+ * @param parser - the OptionParser to use.
+ */
+ public void setSupportedOptions( OptionParser parser );
+
+ /**
+ * Consumes any options that were specified on the command line.
+ *
+ * @param options the OptionSet that the main driver is using. Implementing
+ * classes should add their supported parameters to the list.
+ *
+ * @throws Exception if there is a problem parsing the command line arguments.
+ * Note that Jisql includes jopt-simple so you can use that
+ * to parse your command line. See
+ * <a href="http://jopt-simple.sourceforge.net/">http://jopt-simple.sourceforge.net/</a>
+ * for more information.
+ *
+ */
+ public void consumeOptions( OptionSet options ) throws Exception;
+
+ /**
+ * Called to output a usage message to the command line window. This
+ * message should contain information on how to call the formatter.
+ *
+ * @param out where to put the usage message.
+ *
+ */
+ public void usage( PrintStream out );
+
+
+ /**
+ * Outputs a header for a query. This is called before any data is
+ * output.
+ *
+ * @param out where to put header output.
+ * @param metaData the ResultSetMetaData for the output.
+ *
+ */
+ public void formatHeader( PrintStream out, ResultSetMetaData metaData ) throws Exception;
+
+ /**
+ * Called to output the data.
+ *
+ * @param out where to put output data.
+ * @param resultSet the ResultSet for the row.
+ * @param metaData the ResultSetMetaData for the row.
+ *
+ */
+ public void formatData( PrintStream out, ResultSet resultSet, ResultSetMetaData metaData ) throws Exception;
+
+ /**
+ * Outputs a footer for a query. This is called after all data has been
+ * exhausted.
+ *
+ * @param out where to put footer output.
+ * @param metaData the ResultSetMetaData for the output.
+ *
+ */
+ public void formatFooter( PrintStream out, ResultSetMetaData metaData ) throws Exception;
+}
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/6781cc9c/jisql/src/main/java/org/apache/util/outputformatter/XMLFormatter.java
----------------------------------------------------------------------
diff --git a/jisql/src/main/java/org/apache/util/outputformatter/XMLFormatter.java b/jisql/src/main/java/org/apache/util/outputformatter/XMLFormatter.java
new file mode 100644
index 0000000..f6ddbb6
--- /dev/null
+++ b/jisql/src/main/java/org/apache/util/outputformatter/XMLFormatter.java
@@ -0,0 +1,129 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.util.outputformatter;
+
+import java.io.PrintStream;
+import java.nio.charset.Charset;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+
+import joptsimple.OptionParser;
+import joptsimple.OptionSet;
+
+
+/**
+ * This is the default XML formatter for Jisql. It outputs data in an
+ * XML format.
+ *
+ */
+public class XMLFormatter implements JisqlFormatter {
+
+ /**
+ * Sets a the option list for this formatter. This is a no-op in the
+ * XMLFormatter.
+ *
+ * @param parser the OptionParser to use.
+ *
+ */
+ public void setSupportedOptions( OptionParser parser ) {
+ /* no options for the XMLFormatter */
+ }
+
+ /**
+ * Consumes any options that were specified on the command line. There are
+ * no options to set for the XMLFormatter so this method is a no-op.
+ *
+ * @param options the OptionSet that the main driver is using.
+ *
+ * @throws Exception if there is a problem parsing the command line arguments.
+ *
+ */
+ public void consumeOptions( OptionSet options ) throws Exception {
+ /* no options for the XMLFormatter */
+ }
+
+ /**
+ * Called to output a usage message to the command line window. This
+ * message should contain information on how to call the formatter.
+ * There are no options to set for the XMLFormatter so this method is
+ * a no-op.
+ *
+ */
+ public void usage( PrintStream out ) {
+ /* no options for the XMLFormatter */
+ }
+
+
+ /**
+ * Outputs a header for a query. For the XMLFormater this outputs the XML
+ * pre-amble. The character encoding defaults to the current character
+ * encoding in use.
+ *
+ * @param out a PrintStream to send any output to.
+ * @param metaData the ResultSetMetaData for the output.
+ *
+ */
+ public void formatHeader( PrintStream out, ResultSetMetaData metaData ) throws Exception {
+ out.print( "<?xml version=\"1.0\" encoding=\"" );
+ out.print( Charset.defaultCharset().displayName().toLowerCase() );
+ out.println( "\" ?>" );
+ }
+
+
+ /**
+ * Called to output the data. Note that for the XMLFormatter null fields are
+ * just output as an empty field.
+ *
+ * @param out the PrintStream to output data to.
+ * @param resultSet the ResultSet for the row.
+ * @param metaData the ResultSetMetaData for the row.
+ *
+ */
+ public void formatData( PrintStream out, ResultSet resultSet, ResultSetMetaData metaData ) throws Exception {
+
+ while( resultSet.next() ) {
+ int numColumns = metaData.getColumnCount();
+
+ for (int i = 1; i <= numColumns; i++) {
+ out.print( "<" );
+ out.print( metaData.getColumnName( i ).trim() );
+ out.print( ">" );
+ String result = resultSet.getString(i);
+ if( !resultSet.wasNull() )
+ out.print( result.trim() );
+ out.print( "</" );
+ out.print( metaData.getColumnName( i ).trim() );
+ out.print( ">" );
+ }
+
+ out.println();
+ }
+ }
+
+
+ /**
+ * Outputs a footer for a query. This method isn't used in the XMLFormatter.
+ *
+ * @param out the PrintStream to output data to.
+ * @param metaData the ResultSetMetaData for the output.
+ *
+ */
+ public void formatFooter( PrintStream out, ResultSetMetaData metaData ) throws Exception {
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/6781cc9c/jisql/src/main/java/org/apache/util/sql/Jisql.java
----------------------------------------------------------------------
diff --git a/jisql/src/main/java/org/apache/util/sql/Jisql.java b/jisql/src/main/java/org/apache/util/sql/Jisql.java
new file mode 100644
index 0000000..f3fab71
--- /dev/null
+++ b/jisql/src/main/java/org/apache/util/sql/Jisql.java
@@ -0,0 +1,734 @@
+ /* Copyright (C) 2004-2011 Scott Dunbar (scott@xigole.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.util.sql;
+
+import java.io.BufferedReader;
+import java.io.Console;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.Driver;
+import java.sql.DriverManager;
+import java.sql.DriverPropertyInfo;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Properties;
+import joptsimple.OptionParser;
+import joptsimple.OptionSet;
+import org.apache.util.outputformatter.JisqlFormatter;
+
+/**
+ * A simple utility to provide an interactive session with a SQL server. This
+ * application is conceptually modeled on the Sybase 'isql' program with,
+ * obviously, strong similarities to Microsoft SQL/Server isql and osql (as
+ * Microsoft got SQL Server from Sybase).
+ * <p>
+ *
+ * The program can act in a similar way to Oracle's sqlplus and PostgreSQL's
+ * psql.
+ * <p>
+ *
+ * A simple command line might look like (this should be all on one line) is: <br>
+ * <code>
+ * java -classpath lib/jisql.jar:<file containing native driver>
+ * org.apache.util.sql.Jisql -user scott -password blah -driver postgresql
+ * -cstring jdbc:postgresql://localhost:5432/scott -c \;
+ * </code>
+ * <p>
+ *
+ * This logs into a PostgreSQL database as the user "scott", password "blah". It
+ * connects to the database named "scott". It uses the command terminator of
+ * ";", just like psql or sqlplus (which is escaped in the example so that it
+ * will not be interpreted by the Unix shell). If you do not use this the
+ * default is the term "go" on a single line like Sybase's isql or MS/SQL's
+ * isql/osql. Note that there is a dependency on <a
+ * href="http://jopt-simple.sourceforge.net/">JOpt Simple</a> in for the base
+ * configuration. Additionally, if you are using the CSVFormatter then it is
+ * dependent on <a href="http://sourceforge.net/projects/javacsv/">Java CSV</a>.
+ * <p>
+ *
+ *
+ * Options:
+ * <ul>
+ * <li><b>-driver </b> This option allows you to specify the JDBC driver class
+ * name of the driver. There are several shortcuts that can be used:
+ * <ul>
+ * <li><b>jconnect4 </b>- short for <code>com.sybase.jdbc.SybDriver</code></li>
+ * <li><b>jconnect5 </b>- short for <code>com.sybase.jdbc2.jdbc.SybDriver</code>
+ * <li><b>jconnect6 </b>- short for <code>com.sybase.jdbc3.jdbc.SybDriver</code>
+ * </li>
+ * <li><b>oraclethin </b>- short for
+ * <code>oracle.jdbc.driver.OracleDriver</code></li>
+ * <li><b>db2app </b>- the DB2 "App" driver -
+ * <code>COM.ibm.db2.jdbc.app.DB2Driver</code></li>
+ * <li><b>db2net </b>- the DB2 "Net" driver -
+ * <code>COM.ibm.db2.jdbc.net.DB2Driver</code></li>
+ * <li><b>mssql </b>- short for
+ * <code>com.microsoft.jdbc.sqlserver.SQLServerDriver</code></li>
+ * <li><b>cloudscape </b>- short for <code>COM.cloudscape.core.JDBCDriver</code>
+ * </li>
+ * <li><b>pointbase </b>- short for
+ * <code>com.pointbase.jdbc.jdbcUniversalDriver</code></li>
+ * <li><b>postgresql </b>- short for <code>org.postgresql.Driver</code></li>
+ * <li><b>mysqlconj </b>- short for <code>com.mysql.jdbc.Driver</code>- the
+ * Connector/J driver for MySQL</li>
+ * <li><b>mysqlcaucho </b>- short for <code>com.caucho.jdbc.mysql.Driver</code>-
+ * the Caucho driver for MySQL</li>
+ * </ul>
+ *
+ * Alternatively, any class name can be specified here. The shortcuts only exist
+ * for those of us who generate more typos than real text :)</li>
+ *
+ * <li><b>-cstring </b> This option allows you to specify the connection string
+ * to the database. This string is driver specific but almost always starts with
+ * "jdbc:". Connection strings for the drivers I have tested look
+ * like:
+ * <ul>
+ * <li><b>jconnect4, jconnect5, jconnect6 </b>- Sybase connection strings take
+ * the form "jdbc:sybase:Tds:[hostname]:[port]/[db_name]"</li>
+ * <li><b>oraclethin </b>- The Oracle "thin" driver connection string
+ * looks like "jdbc:oracle:thin:@[hostname]:[port]:[oracle sid]"</li>
+ * <li><b>db2app </b>- The DB2 "App" driver connection string looks
+ * like "jdbc:db2:[db_name]"</li>
+ * <li><b>db2net </b>- The DB2 "Net" driver connection string looks
+ * like "jdbc:db2://[hostname]:[port]/[db_name]"</li>
+ * <li><b>mssql </b>- The MS/SQL driver connection string looks like
+ * "jdbc:microsoft:sqlserver://[hostname]:[port]/[db_name]"</li>
+ * <li><b>cloudscape </b>- The Cloudscape driver connection string looks like
+ * "jdbc:cloudscape:[db_name];create=true;autocommit=false"</li>
+ * <li><b>pointbase </b>- The Pointbase driver connection string looks like
+ * "jdbc:pointbase:server://[hostname]:[port]/[db_name]"</li>
+ * <li><b>postgresql </b>- The PostgreSQL driver connection string looks like
+ * "jdbc:postgresql://[hostname]:[port]/[db_name]"</li>
+ * <li><b>mysqlconj </b>- The MySQL Connector/J driver connection string looks
+ * like "jdbc:mysql://[hostname]:[port]/[db_name]"</li>
+ * <li><b>mysqlcaucho </b>- The MySQL Cahcho driver connection string looks like
+ * "jdbc:mysql-caucho://[hostname]:[port]/[db_name]"</li>
+ * </ul>
+ *
+ * <b>Important </b>- each JDBC vendor has other flags and parameters that can
+ * be passed on the connection string. You should look at the documentation for
+ * your JDBC driver for more information. The strings listed are just a sample
+ * and may change with a new release of the driver. None of these strings are
+ * coded within the application - the list is provided for reference only.</li>
+ *
+ * <li><b>-user or -u </b> The user name to use to log into the database with.</li>
+ * <li><b>-password or -p </b> The password to use to log into the database
+ * with. If this option is missing then the program asks for the password.</li>
+ * <li><b>-c </b> The "command terminator" to use. By default this
+ * application uses the string "go" (case insensitive) on a line by
+ * itself to determine when to send the string buffer to the database. You may
+ * specify something else with the -c option. For example, users of Oracle may
+ * prefer either the ";" (semi-colon) character or the "/"
+ * (forwardslash) character as that is what sqlplus uses. This string may occur
+ * as a standalone line or at the end of a particular line.</li>
+ * <li><b>-pf</b> Optional file to specify the password. This prevents having to
+ * have it visible when looking at a process status. The first line of the file
+ * is read and used as the password. If both the command line password and this
+ * option are specified the command line password is used.</li>
+ * <li><b>-input </b> The name of a file to read commands from instead of
+ * System.in.</li>
+ * <li><b>-query </b> An optional single query to run instead of interacting
+ * with the command line or a file. <b>Note</b> - the command <i>must</i> have a
+ * command terminator. So, for example, your command line may be something like
+ * "-c \; -query "select * from blah;". If you do not include the command
+ * terminator then the command will hang, waiting for you to enter the default
+ * "go".</li>
+ * <li><b>-debug </b> This turns on some internal debugging code. Not generally
+ * useful.</li>
+ * <li><b>-driverinfo </b> Allows you to print some information that the driver
+ * returns. Generally not very useful in all but a few cases.</li>
+ * <li><b>-formatter</b> Optionally specify a class name or short cut to format
+ * the output. There are three built in short cuts:
+ * <ul>
+ * <li><b>csv</b> output the data in CSV format.</li>
+ * <li><b>xml</b> output the data in XML format.</li>
+ * <li><b>default</b> (does not have to be specified) - output the format in the
+ * "normal" format.</li>
+ * </ul>
+ * Otherwise, this is a class name that implements
+ * org.apache.util.outputformatter.JisqlFormatter. See the code for more
+ * information on implementing your own output formatter.</li>
+ * </ul>
+ * <p>
+ *
+ * </p>
+ * The included default formatter supports the following command line options:
+ * <ul>
+ * <li><b>-noheader</b> do not print the header column info.</li>
+ * <li><b>-spacer</b> The character to use for "empty" space. This
+ * defaults to the space character. From mrider - "I added the ability to
+ * specify the spacer for columns - which used to be the single char ' '. I did
+ * this because of brain-dead Windows' command line copy/paste. It seems that
+ * when a line of text ends in space, copy does not copy that space. Which makes
+ * it difficult to copy/paste into another program. This can probably be ignored
+ * most of the time."</li>
+ * <li><b>-w</b>Specifies the maximum field width for a column. By default jisql
+ * defaults columns to a maximum width of 2048. By specifying a value
+ * for this jisql with truncate the output of columns that are wider than this
+ * parameter.</li>
+ * <li><b>-delimiter</b> Specify a single character delimiter for columns.</li>
+ * <li><b>-trim</b> trim the spaces from columns.</li>
+ * <li><b>-nonull</b> print an empty string instead of the word "NULL"
+ * when there is a null value.
+ * <li>
+ * <li><b>-left</b> left justify the output</li>
+ * <li><b>-debug</b> print debugging information about the result set.</li>
+ * </ul>
+ * <p>
+ *
+ * </p>
+ * The include CSV formatter supports the following command line options:
+ * <ul>
+ * <li><b>-delimiter</b> specifies the delimiter to use. By default a comma is
+ * used</li>
+ * <li><b>-colnames</b> if included then column names are printed as the first
+ * line of output. By default they are not included</li>
+ * </ul>
+ * <p>
+ *
+ * </p>
+ * The included XML formatter does not have any additional output options.
+ * <p>
+ *
+ * </p>
+ */
+public class Jisql {
+ private static final String sybaseJConnect6DriverName = "com.sybase.jdbc3.jdbc.SybDriver";
+ private static final String sybaseJConnect5DriverName = "com.sybase.jdbc2.jdbc.SybDriver";
+ private static final String sybaseJConnect4DriverName = "com.sybase.jdbc.SybDriver";
+ private static final String oracleThinDriverName = "oracle.jdbc.driver.OracleDriver";
+ private static final String db2AppDriverName = "COM.ibm.db2.jdbc.app.DB2Driver";
+ private static final String db2NetDriverName = "COM.ibm.db2.jdbc.net.DB2Driver";
+ private static final String cloudscapeDriverName = "COM.cloudscape.core.JDBCDriver";
+ private static final String msqlDriverName = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
+ private static final String pointbaseDriverName = "com.pointbase.jdbc.jdbcUniversalDriver";
+ private static final String postgresqlDriverName = "org.postgresql.Driver";
+ private static final String mySQLConnectJDriverName = "com.mysql.jdbc.Driver";
+ private static final String mySQLCauchoDriverName = "com.caucho.jdbc.mysql.Driver";
+
+ private static final String defaultFormatterClassName = "org.apache.util.outputformatter.DefaultFormatter";
+ private static final String csvFormatterClassName = "org.apache.util.outputformatter.CSVFormatter";
+ private static final String xmlFormatterClassName = "org.apache.util.outputformatter.XMLFormatter";
+
+ private String driverName = null;
+ private String connectString = null;
+ private String userName = null;
+ private String password = null;
+ private String passwordFileName = null;
+ private String formatterClassName = defaultFormatterClassName;
+
+ private JisqlFormatter formatter = null;
+
+ private Connection connection = null;
+ private boolean printDebug = false;
+ private boolean printDriverDetails = false;
+ private Driver driver = null;
+ private Properties props = null;
+ private String inputFileName = null;
+ private String commandTerminator = "go";
+ private String inputQuery = null;
+
+ /**
+ * Runs Jisql with the command line arguments provided.
+ *
+ */
+ public static void main(String argv[]) {
+ Jisql jisql = new Jisql();
+
+ try {
+ jisql.parseArgs(argv);
+ }
+ catch (Throwable t) {
+ t.printStackTrace();
+ jisql.usage();
+ System.exit(1);
+ }
+
+ try {
+ jisql.run();
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+
+ System.exit(0);
+ }
+
+ public void run() throws Exception {
+
+ try {
+ driver = (Driver) Class.forName(driverName).newInstance();
+ props = new Properties();
+
+ props.put("user", userName);
+ if (password != null)
+ props.put("password", password);
+
+ connection = DriverManager.getConnection(connectString, props);
+ if (printDriverDetails) {
+ printDriverInfo();
+ }
+ else {
+ if(connectString.toLowerCase().startsWith("jdbc:mysql") && inputFileName!=null){
+ MySQLPLRunner scriptRunner = new MySQLPLRunner(connection, false, true,printDebug);
+ scriptRunner.setDelimiter(commandTerminator,false);
+ scriptRunner.runScript(new FileReader(inputFileName));
+ }else{
+ doIsql();
+ }
+ }
+ }
+ catch (SQLException sqle) {
+ printAllExceptions(sqle);
+ }
+ catch (ClassNotFoundException cnfe) {
+ System.err.println("Cannot find the driver class \"" + driverName + "\" in the current classpath.");
+ }
+ catch (InstantiationException ie) {
+ System.err.println("Cannot instantiate the driver class \"" + driverName + "\"");
+ ie.printStackTrace(System.err);
+ }
+ catch (IllegalAccessException iae) {
+ System.err.println("Cannot instantiate the driver class \"" + driverName + "\" because of an IllegalAccessException");
+ iae.printStackTrace(System.err);
+ }
+ finally {
+ if (connection != null) {
+ try {
+ connection.close();
+ }
+ catch (SQLException ignore) {
+ /* ignored */
+ }
+ }
+ }
+ }
+
+ /**
+ * The main loop for the Jisql program. This method handles the input from
+ * either a command line or from a file. Output is handled through the
+ * Formatter.
+ *
+ * @throws SQLException
+ * if an exception occurs.
+ *
+ */
+ public void doIsql() throws SQLException {
+ BufferedReader reader = null;
+ Statement statement = null;
+ ResultSet resultSet = null;
+ ResultSetMetaData resultSetMetaData = null;
+ StringBuffer query = null;
+
+ if (inputFileName != null) {
+ try {
+ reader = new BufferedReader(new FileReader(inputFileName));
+ }
+ catch (FileNotFoundException fnfe) {
+ System.err.println("Unable to open \"" + inputFileName + "\"");
+ fnfe.printStackTrace(System.err);
+ return;
+ }
+ }
+ else {
+ reader = new BufferedReader(new InputStreamReader(System.in));
+ }
+ if(printDebug)
+ printAllExceptions(connection.getWarnings());
+ statement = connection.createStatement();
+ connection.clearWarnings();
+ String trimmedLine=null;
+ while (true) {
+ int linecount = 1;
+ query = new StringBuffer();
+
+ try {
+ if ((inputFileName == null) && (inputQuery == null))
+ System.out.print("\nEnter a query:\n");
+
+ while (true) {
+ if ((inputFileName == null) && (inputQuery == null)) {
+ System.out.print(linecount++ + " > ");
+ System.out.flush();
+ }
+
+ String line = null;
+ if (inputQuery == null)
+ line = reader.readLine();
+ else
+ line = inputQuery.toString();
+
+ if (line == null || line.equalsIgnoreCase("quit") || line.equalsIgnoreCase("exit")){
+ if ((inputFileName != null) && (inputQuery != null)) {
+ break;
+ }else{
+ return;
+ }
+ }
+
+ if (line.equals("reset")) {
+ query = new StringBuffer();
+ break;
+ }
+ trimmedLine=line.trim();
+ if (trimmedLine.startsWith("--") ||trimmedLine.length()<1) {
+ continue;
+ }
+ if(connectString.toLowerCase().startsWith("jdbc:oracle") && inputFileName!=null){
+ if (trimmedLine.startsWith("/") ||trimmedLine.length()<2) {
+ continue;
+ }
+ }
+
+ if (line.trim().equalsIgnoreCase(commandTerminator) || line.trim().endsWith(commandTerminator)) {
+ if (line.trim().endsWith(commandTerminator)) {
+ line = line.substring(0, line.length() - commandTerminator.length());
+ query.append("\n");
+ query.append(line);
+ }
+ break;
+ }
+
+ query.append("\n");
+ query.append(line);
+ }
+
+ if (query.toString().length() == 0)
+ continue;
+
+ if (printDebug)
+ System.out.println("executing: " + query.toString());
+
+ boolean moreResults = statement.execute(query.toString());
+ int rowsAffected = 0;
+ do {
+ if(printDebug)
+ printAllExceptions(statement.getWarnings());
+ statement.clearWarnings();
+ if (moreResults) {
+ resultSet = statement.getResultSet();
+ if(printDebug)
+ printAllExceptions(resultSet.getWarnings());
+ resultSet.clearWarnings();
+ resultSetMetaData = resultSet.getMetaData();
+
+ formatter.formatHeader(System.out, resultSetMetaData);
+ formatter.formatData(System.out, resultSet, resultSetMetaData);
+ formatter.formatFooter(System.out, resultSetMetaData);
+
+ int rowsSelected = statement.getUpdateCount();
+
+ if (rowsSelected >= 0 && printDebug) {
+ System.out.println(rowsSelected + " rows affected.");
+ }
+ }
+ else {
+ rowsAffected = statement.getUpdateCount();
+ if (printDebug)
+ printAllExceptions(statement.getWarnings());
+ statement.clearWarnings();
+ if (rowsAffected >= 0 && printDebug) {
+ System.out.println(rowsAffected + " rows affected.");
+ }
+ }
+
+ //
+ // I was having problems with the PostgreSQL driver throwing
+ // a NullPointerException here so I just catch it and tell
+ // the loop that it is done if it happens.
+ //
+ try {
+ moreResults = statement.getMoreResults();
+ }
+ catch (NullPointerException npe) {
+ moreResults = false;
+ }
+ }
+
+ while (moreResults || rowsAffected != -1);
+ }
+ catch (SQLException sqle) {
+ printAllExceptions(sqle);
+ statement.cancel();
+ statement.clearWarnings();
+ }
+ catch (Exception e) {
+ e.printStackTrace(System.err);
+ }
+
+ if (inputQuery != null)
+ return;
+ }
+ }
+
+ /**
+ * Prints some information about the JDBC driver in use.
+ *
+ * @throws SQLException
+ * if one of the methods called does.
+ *
+ */
+ private void printDriverInfo() throws SQLException {
+ System.out.println("driver.getMajorVersion() is " + driver.getMajorVersion());
+ System.out.println("driver.getMinorVersion() is " + driver.getMinorVersion());
+ System.out.println("driver is " + (driver.jdbcCompliant() ? "" : "not ") + "JDBC compliant");
+
+ DriverPropertyInfo info[] = driver.getPropertyInfo(connectString, props);
+
+ for (int i = 0; i < info.length; i++) {
+ System.out.println("driver property named \"" + info[i].name + "\"");
+ if (info[i].choices != null) {
+ System.out.println("choices:");
+ for (int j = 0; j < info[i].choices.length; j++)
+ System.out.println("\tchoice " + j + ": \"" + info[i].choices[j] + "\"");
+ }
+ System.out.println("description: \"" + info[i].description + "\"");
+ System.out.println("required parameter?: \"" + info[i].required + "\"");
+ System.out.println("current value: \"" + info[i].value + "\"\n");
+ }
+
+ DatabaseMetaData metaData = connection.getMetaData();
+
+ System.out.println("metaData.getDatabaseProductName(): \"" + metaData.getDatabaseProductName() + "\"");
+ System.out.println("metaData.getDatabaseProductVersion(): \"" + metaData.getDatabaseProductVersion() + "\"");
+
+ System.out.println("metaData.getDriverName(): \"" + metaData.getDriverName() + "\"");
+ System.out.println("metaData.getDriverVersion(): \"" + metaData.getDriverVersion() + "\"");
+ }
+
+ /**
+ * Parse the command line arguments. This method parses what is needed for
+ * the Jisql driver program and lets the configured formatter do the same.
+ *
+ * @param argv the command line arguments.
+ *
+ * @throws Exception if there are any errors parsing the command line arguments.
+ *
+ */
+ public void parseArgs(String argv[]) throws Throwable {
+ //
+ // I'm sure that there has to be a better way but I couldn't find a
+ // command lineparser that would let me ignore unknown arguments. so
+ // walk through the list once to find the formatter. then, use the
+ // command line parser to do it "for real"
+ //
+ for (int argumentIndex = 0; argumentIndex < argv.length; argumentIndex++) {
+ if (argv[argumentIndex].equals("-formatter")) {
+ formatterClassName = argv[argumentIndex + 1];
+ break;
+ }
+ }
+
+ if (formatterClassName.compareToIgnoreCase("csv") == 0)
+ formatterClassName = csvFormatterClassName;
+ else if (formatterClassName.compareToIgnoreCase("xml") == 0)
+ formatterClassName = xmlFormatterClassName;
+ else if (formatterClassName.compareToIgnoreCase("default") == 0)
+ formatterClassName = defaultFormatterClassName;
+
+ formatter = (JisqlFormatter) Class.forName(formatterClassName).newInstance();
+
+ OptionParser parser = new OptionParser();
+ parser.posixlyCorrect(false);
+
+ parser.accepts("c").withRequiredArg().ofType(String.class);
+ parser.accepts("cstring").withRequiredArg().ofType(String.class);
+ parser.accepts("debug");
+ parser.accepts("driver").withRequiredArg().ofType(String.class);
+ parser.accepts("driverinfo");
+ parser.accepts("formatter").withRequiredArg().ofType(String.class);
+ parser.accepts("help");
+ parser.accepts("input").withRequiredArg().ofType(String.class);
+ parser.accepts("password").withOptionalArg().ofType(String.class);
+ parser.accepts("p").withOptionalArg().ofType(String.class);
+ parser.accepts("pf").withRequiredArg().ofType(String.class);
+ parser.accepts("query").withRequiredArg().ofType(String.class);
+ parser.accepts("user").withRequiredArg().ofType(String.class);
+ parser.accepts("u").withRequiredArg().ofType(String.class);
+
+ formatter.setSupportedOptions(parser);
+
+ OptionSet options = parser.parse(argv);
+
+ if (options.has("help")) {
+ usage();
+ System.exit(1);
+ }
+
+ if (options.has("driver")) {
+ driverName = (String) options.valueOf("driver");
+
+ if (driverName.compareToIgnoreCase("jconnect4") == 0)
+ driverName = sybaseJConnect4DriverName;
+ else if (driverName.compareToIgnoreCase("jconnect5") == 0)
+ driverName = sybaseJConnect5DriverName;
+ else if (driverName.compareToIgnoreCase("jconnect6") == 0)
+ driverName = sybaseJConnect6DriverName;
+ else if (driverName.compareToIgnoreCase("oraclethin") == 0)
+ driverName = oracleThinDriverName;
+ else if (driverName.compareToIgnoreCase("db2app") == 0)
+ driverName = db2AppDriverName;
+ else if (driverName.compareToIgnoreCase("db2net") == 0)
+ driverName = db2NetDriverName;
+ else if (driverName.compareToIgnoreCase("cloudscape") == 0)
+ driverName = cloudscapeDriverName;
+ else if (driverName.compareToIgnoreCase("mssql") == 0)
+ driverName = msqlDriverName;
+ else if (driverName.compareToIgnoreCase("pointbase") == 0)
+ driverName = pointbaseDriverName;
+ else if (driverName.compareToIgnoreCase("postgresql") == 0)
+ driverName = postgresqlDriverName;
+ else if (driverName.compareToIgnoreCase("mysqlconj") == 0)
+ driverName = mySQLConnectJDriverName;
+ else if (driverName.compareToIgnoreCase("mysqlcaucho") == 0)
+ driverName = mySQLCauchoDriverName;
+ }
+
+ connectString = (String) options.valueOf("cstring");
+
+ if (options.has("c"))
+ commandTerminator = (String) options.valueOf("c");
+
+ if (options.has("debug"))
+ printDebug = true;
+
+ if (options.has("user"))
+ userName = (String) options.valueOf("user");
+ else if (options.has("u"))
+ userName = (String) options.valueOf("u");
+
+ if (options.has("password"))
+ password = (String) options.valueOf("password");
+ else if (options.has("p"))
+ password = (String) options.valueOf("p");
+
+ if (options.has("driverinfo"))
+ printDriverDetails = true;
+
+ if (options.has("input"))
+ inputFileName = (String) options.valueOf("input");
+
+ if (options.has("pf"))
+ passwordFileName = (String) options.valueOf("pf");
+
+ if (options.has("query"))
+ inputQuery = (String) options.valueOf("query");
+
+ if (driverName == null)
+ throw new Exception("driver name must exist");
+
+ if (connectString == null)
+ throw new Exception("connect string must exist");
+
+ if (userName == null)
+ throw new Exception("user name must exist");
+
+ if ((password == null) && (passwordFileName == null)) {
+ Console console = System.console();
+ password = new String( console.readPassword("Password (hit enter for no password): ") );
+ }
+ else if (password == null) {
+ File passwordFile = null;
+ BufferedReader reader = null;
+
+ passwordFile = new File(passwordFileName);
+ if (!passwordFile.exists())
+ throw new Exception("the password file \"" + passwordFileName + "\" does not exist");
+
+ if (!passwordFile.isFile())
+ throw new Exception("the password file \"" + passwordFileName + "\" is not a normal file");
+
+ if (!passwordFile.canRead())
+ throw new Exception("the password file \"" + passwordFileName + "\" is not readable");
+
+ try {
+ reader = new BufferedReader(new FileReader(passwordFile));
+ password = reader.readLine().trim();
+ }
+ catch (Exception e) {
+ throw new Exception("An error occured reading the password file", e);
+ }
+ finally {
+ if (reader != null) {
+ try {
+ reader.close();
+ }
+ catch (Exception ignore) { /* ignored */
+ }
+ }
+ }
+ }
+
+ formatter.consumeOptions(options);
+ }
+
+ /**
+ * Walks through a SQLException and prints out every exception.
+ *
+ * @param sqle the Exception to print
+ *
+ */
+ private void printAllExceptions(SQLException sqle) {
+ while (sqle != null) {
+ System.err.println("SQLException : " + "SQL state: " + sqle.getSQLState() + " " + sqle.toString() + " ErrorCode: "
+ + sqle.getErrorCode());
+ sqle = sqle.getNextException();
+ }
+ }
+
+ /**
+ * Prints out the usage message for the Jisql driver and the configured
+ * formatter.
+ *
+ */
+ private void usage() {
+ System.err.println();
+ System.err.println("usage: java " + getClass().getName() +
+ " -driver driver -cstring connect_string -user|-u username -password|-p password [-pf password_file] " +
+ "[-c command_term] [-input file_name] [-debug] [-driverinfo] [-formatter formatter]");
+ System.err.println("where:");
+ System.err
+ .println("\t-driver specifies the JDBC driver to use. There are several builtin shortcuts - see the docs for details.");
+ System.err.println("\t-cstring specifies the connection string to use. These are driver specific.");
+ System.err.println("\t-user specifies a user name to log into a database server with.");
+ System.err.println("\t-password specifies the user name to log into a database server with.");
+ System.err.println("\t-pf specifies the name of a file that contains the password to log into a database server with.");
+ System.err.println("\t The first line of file should contain the password and nothing else.");
+ System.err.println("\t-c specifies the command terminator. The default is \"" + commandTerminator + "\"");
+ System.err.println("\t-input specifies a file name to read commands from.");
+ System.err
+ .println("\t-query specifies an optional single query to run instead of interacting with the command line or a file.");
+ System.err.println("\t Note that the command must include a command terminator or the command will hang");
+ System.err.println("\t-debug prints to stdout (System.out) debugging information");
+ System.err.println("\t-driverinfo prints to stdout (System.out) detailed driver information and then exits");
+ System.err
+ .println("\t-formatter specifies either a class name or a pre-configured output formatter. See the docs for details.");
+
+ if (formatter != null) {
+ System.err.println("Additional command line arguments of the " + formatter.getClass().getName() + " class are");
+ formatter.usage(System.err);
+ }
+
+ System.err.println();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/6781cc9c/jisql/src/main/java/org/apache/util/sql/MaskingThread.java
----------------------------------------------------------------------
diff --git a/jisql/src/main/java/org/apache/util/sql/MaskingThread.java b/jisql/src/main/java/org/apache/util/sql/MaskingThread.java
new file mode 100644
index 0000000..e938e69
--- /dev/null
+++ b/jisql/src/main/java/org/apache/util/sql/MaskingThread.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.util.sql;
+
+
+public class MaskingThread extends Thread
+{
+ private boolean stop = false;
+ private String prompt = null;
+
+ /**
+ * @param thePrompt The prompt displayed to the user
+ */
+ public MaskingThread(String thePrompt)
+ {
+ prompt = thePrompt;
+ }
+
+ /**
+ * Begin masking until asked to stop.
+ */
+ public void run()
+ {
+ while (!stop)
+ {
+ try
+ {
+ // attempt masking at this rate (refresh every 1 ms.)
+ sleep(1);
+ }
+ catch (InterruptedException iex)
+ {
+ iex.printStackTrace();
+ }
+ if (!stop)
+ {
+//
+// sd - note what this does. If your prompt is really short
+// and your password is really long this won't work - some
+// characters will become visible
+//
+ System.out.print( "\r" + prompt + " \r" + prompt );
+ }
+ System.out.flush();
+ }
+ }
+
+ /**
+ * Instruct the thread to stop masking.
+ */
+ public void stopMasking()
+ {
+ stop = true;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/6781cc9c/jisql/src/main/java/org/apache/util/sql/MySQLPLRunner.java
----------------------------------------------------------------------
diff --git a/jisql/src/main/java/org/apache/util/sql/MySQLPLRunner.java b/jisql/src/main/java/org/apache/util/sql/MySQLPLRunner.java
new file mode 100644
index 0000000..dc5de79
--- /dev/null
+++ b/jisql/src/main/java/org/apache/util/sql/MySQLPLRunner.java
@@ -0,0 +1,345 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.util.sql;
+
+
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.LineNumberReader;
+import java.io.PrintWriter;
+import java.io.Reader;
+import java.sql.Connection;
+import java.sql.Driver;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.List;
+import java.util.Properties;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+
+public class MySQLPLRunner {
+
+ private static final String DEFAULT_DELIMITER = ";";
+ private Connection connection;
+ private boolean stopOnError;
+ private boolean autoCommit;
+ private PrintWriter logWriter = new PrintWriter(System.out);
+ private PrintWriter errorLogWriter = new PrintWriter(System.err);
+ private String delimiter = DEFAULT_DELIMITER;
+ private boolean fullLineDelimiter = false;
+ private static final String DELIMITER_LINE_REGEX = "(?i)delimiter.+";
+ private static final String DELIMITER_LINE_SPLIT_REGEX = "(?i)delimiter";
+ private boolean printDebug = false;
+ /**
+ * Default constructor
+ */
+ public MySQLPLRunner(Connection connection, boolean autoCommit,
+ boolean stopOnError,boolean printDebug) {
+ this.connection = connection;
+ this.autoCommit = autoCommit;
+ this.stopOnError = stopOnError;
+ this.printDebug=printDebug;
+ }
+
+ public void setDelimiter(String delimiter, boolean fullLineDelimiter) {
+ this.delimiter = delimiter;
+ this.fullLineDelimiter = fullLineDelimiter;
+ }
+
+ /**
+ * Setter for logWriter property
+ *
+ * @param logWriter
+ * - the new value of the logWriter property
+ */
+ public void setLogWriter(PrintWriter logWriter) {
+ this.logWriter = logWriter;
+ }
+
+ /**
+ * Setter for errorLogWriter property
+ *
+ * @param errorLogWriter
+ * - the new value of the errorLogWriter property
+ */
+ public void setErrorLogWriter(PrintWriter errorLogWriter) {
+ this.errorLogWriter = errorLogWriter;
+ }
+
+ /**
+ * Runs an SQL script (read in using the Reader parameter)
+ *
+ * @param reader
+ * - the source of the script
+ */
+ public void runScript(Reader reader) throws IOException, SQLException {
+ try {
+ boolean originalAutoCommit = connection.getAutoCommit();
+ try {
+ if (originalAutoCommit != this.autoCommit) {
+ connection.setAutoCommit(this.autoCommit);
+ }
+ runScript(connection, reader);
+ } finally {
+ connection.setAutoCommit(originalAutoCommit);
+ }
+ } catch (IOException e) {
+ throw e;
+ } catch (SQLException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new RuntimeException("Error running script. Cause: " + e, e);
+ }
+ }
+
+ /**
+ * Runs an SQL script (read in using the Reader parameter) using the
+ * connection passed in
+ *
+ * @param conn
+ * - the connection to use for the script
+ * @param reader
+ * - the source of the script
+ * @throws SQLException
+ * if any SQL errors occur
+ * @throws IOException
+ * if there is an error reading from the Reader
+ */
+ private void runScript(Connection conn, Reader reader) throws IOException,
+ SQLException {
+ StringBuffer command = null;
+ try {
+ LineNumberReader lineReader = new LineNumberReader(reader);
+ String line = null;
+ while ((line = lineReader.readLine()) != null) {
+ if (command == null) {
+ command = new StringBuffer();
+ }
+ String trimmedLine = line.trim();
+
+ if (trimmedLine.startsWith("--")) {
+ //println(trimmedLine);
+ } else if (trimmedLine.length() < 1
+ || trimmedLine.startsWith("//")) {
+ // Do nothing
+ } else if (trimmedLine.length() < 1
+ || trimmedLine.startsWith("--")) {
+ // Do nothing
+ } else if (!fullLineDelimiter
+ && trimmedLine.endsWith(getDelimiter())
+ || fullLineDelimiter
+ && trimmedLine.equals(getDelimiter())) {
+
+
+ Pattern pattern = Pattern.compile(DELIMITER_LINE_REGEX);
+ Matcher matcher = pattern.matcher(trimmedLine);
+ if (matcher.matches()) {
+ setDelimiter(trimmedLine.split(DELIMITER_LINE_SPLIT_REGEX)[1].trim(), fullLineDelimiter);
+ continue;
+ /*line = lineReader.readLine();
+ if (line == null) {
+ break;
+ }
+ trimmedLine = line.trim();*/
+ }
+
+ if(line!=null && line.endsWith(getDelimiter()) && !DEFAULT_DELIMITER.equalsIgnoreCase(getDelimiter())){
+ command.append(line.substring(0, line.lastIndexOf(getDelimiter())));
+ }else{
+ command.append(line);
+ }
+
+ command.append(" ");
+ Statement statement = conn.createStatement();
+ if(printDebug)
+ println(command);
+ //System.out.println(getDelimiter());
+ boolean hasResults = false;
+ if (stopOnError) {
+ hasResults = statement.execute(command.toString());
+ } else {
+ try {
+ statement.execute(command.toString());
+ } catch (SQLException e) {
+ e.fillInStackTrace();
+ printlnError("Error executing: " + command);
+ printlnError(e);
+ }
+ }
+
+ if (autoCommit && !conn.getAutoCommit()) {
+ conn.commit();
+ }
+
+ ResultSet rs = statement.getResultSet();
+ if (hasResults && rs != null) {
+ ResultSetMetaData md = rs.getMetaData();
+ int cols = md.getColumnCount();
+ for (int i = 0; i < cols; i++) {
+ String name = md.getColumnLabel(i);
+ print(name + "\t");
+ }
+ println("");
+ while (rs.next()) {
+ for (int i = 1; i <= cols; i++) {
+ String value = rs.getString(i);
+ print(value + "\t");
+ }
+ println("");
+ }
+ }
+
+ command = null;
+ try {
+ if(rs!=null){
+ rs.close();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ try {
+ statement.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ // Ignore to workaround a bug in Jakarta DBCP
+ }
+ Thread.yield();
+ } else {
+ Pattern pattern = Pattern.compile(DELIMITER_LINE_REGEX);
+ Matcher matcher = pattern.matcher(trimmedLine);
+ if (matcher.matches()) {
+ setDelimiter(trimmedLine.split(DELIMITER_LINE_SPLIT_REGEX)[1].trim(), fullLineDelimiter);
+ continue;
+ /*line = lineReader.readLine();
+ if (line == null) {
+ break;
+ }
+ trimmedLine = line.trim();*/
+ }
+ command.append(line);
+ command.append(" ");
+ }
+ }
+ if (!autoCommit) {
+ conn.commit();
+ }
+ } catch (SQLException e) {
+ e.fillInStackTrace();
+ printlnError("Error executing: " + command);
+ printlnError(e);
+ throw e;
+ } catch (IOException e) {
+ e.fillInStackTrace();
+ printlnError("Error executing: " + command);
+ printlnError(e);
+ throw e;
+ } finally {
+ conn.rollback();
+ flush();
+ }
+ }
+
+ private String getDelimiter() {
+ return delimiter;
+ }
+
+ private void print(Object o) {
+ if (logWriter != null) {
+ System.out.print(o);
+ }
+ }
+
+ private void println(Object o) {
+ if (logWriter != null) {
+ logWriter.println(o);
+ }
+ }
+
+ private void printlnError(Object o) {
+ if (errorLogWriter != null) {
+ errorLogWriter.println(o);
+ }
+ }
+
+ private void flush() {
+ if (logWriter != null) {
+ logWriter.flush();
+ }
+ if (errorLogWriter != null) {
+ errorLogWriter.flush();
+ }
+ }
+
+ public static void main(String args[]){
+ // Creating object of ScriptRunner class
+ Connection con = null;
+ String driverName = "com.mysql.jdbc.Driver";
+ Properties props = null;
+ try {
+ Driver driver = (Driver) Class.forName(driverName).newInstance();
+ props = new Properties();
+
+ props.put("user", "root");
+
+ props.put("password", "root");
+ String connectString = "jdbc:mysql://localhost:3306/ranger";
+ con = DriverManager.getConnection(connectString, props);
+
+
+ MySQLPLRunner scriptRunner = new MySQLPLRunner(con, false, true,true);
+ String aSQLScriptFilePath = "/disk1/zero/jisql-2.0.11/xa_core_db.sql";
+
+
+ // Executing SQL Script
+ scriptRunner.runScript(new FileReader(aSQLScriptFilePath));
+
+
+ }
+ catch (SQLException sqle) {
+ sqle.printStackTrace();
+ }
+ catch (ClassNotFoundException cnfe) {
+ System.err.println("Cannot find the driver class \"" + driverName + "\" in the current classpath.");
+ }
+ catch (InstantiationException ie) {
+ System.err.println("Cannot instantiate the driver class \"" + driverName + "\"");
+ ie.printStackTrace(System.err);
+ }
+ catch (IllegalAccessException iae) {
+ System.err.println("Cannot instantiate the driver class \"" + driverName + "\" because of an IllegalAccessException");
+ iae.printStackTrace(System.err);
+ }catch (Exception sqle) {
+ sqle.printStackTrace();
+ }
+ finally {
+ if (con != null) {
+ try {
+ con.close();
+ }
+ catch (SQLException ignore) {
+ /* ignored */
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/6781cc9c/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 9e4e151..bf6b1d3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -74,6 +74,7 @@
</mailingLists>
<modules>
+ <module>jisql</module>
<module>agents-audit</module>
<module>agents-common</module>
<module>agents-cred</module>
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/6781cc9c/src/main/assembly/admin-web.xml
----------------------------------------------------------------------
diff --git a/src/main/assembly/admin-web.xml b/src/main/assembly/admin-web.xml
index 6eb417b..e7cbf3a 100644
--- a/src/main/assembly/admin-web.xml
+++ b/src/main/assembly/admin-web.xml
@@ -102,7 +102,28 @@
<include>org.apache.ranger:credentialbuilder</include>
</includes>
</moduleSet>
-
+<moduleSet>
+ <binaries>
+ <includeDependencies>false</includeDependencies>
+ <outputDirectory>/jisql/lib</outputDirectory>
+ <unpack>false</unpack>
+ <directoryMode>755</directoryMode>
+ <fileMode>644</fileMode>
+ <dependencySets>
+ <dependencySet>
+ <outputDirectory>/jisql/lib</outputDirectory>
+ <unpack>false</unpack>
+ <includes>
+ <include>net.sourceforge.javacsv:javacsv</include>
+ <include>net.sf.jopt-simple:jopt-simple</include>
+ </includes>
+ </dependencySet>
+ </dependencySets>
+ </binaries>
+ <includes>
+ <include>org.apache.ranger:jisql</include>
+ </includes>
+ </moduleSet>
</moduleSets>
<fileSets>