1334 lines
		
	
	
		
			53 KiB
		
	
	
	
		
			Java
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			1334 lines
		
	
	
		
			53 KiB
		
	
	
	
		
			Java
		
	
	
		
			Executable File
		
	
	
	
	
#!/usr/bin/env compileAndGo
 | 
						|
# -*- coding: utf-8 mode: java -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
 | 
						|
compiler=javac
 | 
						|
mainClass=sqlcsv
 | 
						|
compileAndGo
 | 
						|
 | 
						|
import java.io.BufferedReader;
 | 
						|
import java.io.BufferedWriter;
 | 
						|
import java.io.Closeable;
 | 
						|
import java.io.File;
 | 
						|
import java.io.FileInputStream;
 | 
						|
import java.io.FileNotFoundException;
 | 
						|
import java.io.FileOutputStream;
 | 
						|
import java.io.FilenameFilter;
 | 
						|
import java.io.IOException;
 | 
						|
import java.io.InputStream;
 | 
						|
import java.io.InputStreamReader;
 | 
						|
import java.io.OutputStreamWriter;
 | 
						|
import java.io.PrintWriter;
 | 
						|
import java.io.Reader;
 | 
						|
import java.io.StringReader;
 | 
						|
import java.io.StringWriter;
 | 
						|
import java.io.Writer;
 | 
						|
import java.lang.reflect.InvocationTargetException;
 | 
						|
import java.math.BigDecimal;
 | 
						|
import java.net.MalformedURLException;
 | 
						|
import java.net.URL;
 | 
						|
import java.net.URLClassLoader;
 | 
						|
import java.nio.charset.Charset;
 | 
						|
import java.sql.Clob;
 | 
						|
import java.sql.Connection;
 | 
						|
import java.sql.Date;
 | 
						|
import java.sql.Driver;
 | 
						|
import java.sql.DriverManager;
 | 
						|
import java.sql.DriverPropertyInfo;
 | 
						|
import java.sql.PreparedStatement;
 | 
						|
import java.sql.ResultSet;
 | 
						|
import java.sql.ResultSetMetaData;
 | 
						|
import java.sql.SQLException;
 | 
						|
import java.sql.Time;
 | 
						|
import java.sql.Timestamp;
 | 
						|
import java.sql.Types;
 | 
						|
import java.text.SimpleDateFormat;
 | 
						|
import java.util.ArrayList;
 | 
						|
import java.util.Enumeration;
 | 
						|
import java.util.Iterator;
 | 
						|
import java.util.List;
 | 
						|
import java.util.Properties;
 | 
						|
import java.util.logging.ConsoleHandler;
 | 
						|
import java.util.logging.Level;
 | 
						|
import java.util.logging.Logger;
 | 
						|
import java.util.regex.Matcher;
 | 
						|
import java.util.regex.Pattern;
 | 
						|
 | 
						|
public class sqlcsv {
 | 
						|
    static final String CLASS_NAME = sqlcsv.class.getName();
 | 
						|
 | 
						|
    static final Logger log = Logger.getLogger(CLASS_NAME);
 | 
						|
    static {
 | 
						|
        ConsoleHandler handler = new ConsoleHandler();
 | 
						|
        handler.setLevel(Level.ALL);
 | 
						|
        log.addHandler(handler);
 | 
						|
        log.setUseParentHandlers(false);
 | 
						|
    }
 | 
						|
 | 
						|
    static final Charset UTF8;
 | 
						|
    static {
 | 
						|
        UTF8 = Charset.forName("UTF-8");
 | 
						|
    }
 | 
						|
 | 
						|
    static final String USER_CONFDIR = System.getProperty("user.home") + "/." + CLASS_NAME;
 | 
						|
 | 
						|
    static final String SYSTEM_CONFDIR = "/etc/" + CLASS_NAME;
 | 
						|
 | 
						|
    static final String DEFAULT_CONFIG = CLASS_NAME + ".properties";
 | 
						|
 | 
						|
    static final String USER_CONFIG = USER_CONFDIR + "/" + DEFAULT_CONFIG,
 | 
						|
            SYSTEM_CONFIG = SYSTEM_CONFDIR + "/" + DEFAULT_CONFIG;
 | 
						|
 | 
						|
    // ------------------------------------------------------------------------
 | 
						|
    public static class ResultSetHelper {
 | 
						|
        public static final int CLOBBUFFERSIZE = 2048;
 | 
						|
 | 
						|
        // note: we want to maintain compatibility with Java 5 VM's
 | 
						|
        // These types don't exist in Java 5
 | 
						|
        protected static final int NVARCHAR = -9, NCHAR = -15, LONGNVARCHAR = -16, NCLOB = 2011;
 | 
						|
 | 
						|
        public static final String[] getColumnNames(ResultSet rs) throws SQLException {
 | 
						|
            List<String> names = new ArrayList<String>();
 | 
						|
            ResultSetMetaData metadata = rs.getMetaData();
 | 
						|
            for (int i = 0; i < metadata.getColumnCount(); i++) {
 | 
						|
                names.add(metadata.getColumnName(i + 1));
 | 
						|
            }
 | 
						|
            String[] nameArray = new String[names.size()];
 | 
						|
            return names.toArray(nameArray);
 | 
						|
        }
 | 
						|
 | 
						|
        public String[] getColumnValues(ResultSet rs) throws SQLException, IOException {
 | 
						|
            List<String> values = new ArrayList<String>();
 | 
						|
            ResultSetMetaData metadata = rs.getMetaData();
 | 
						|
            for (int i = 0; i < metadata.getColumnCount(); i++) {
 | 
						|
                values.add(getColumnValue(rs, metadata.getColumnType(i + 1), i + 1));
 | 
						|
            }
 | 
						|
            String[] valueArray = new String[values.size()];
 | 
						|
            return values.toArray(valueArray);
 | 
						|
        }
 | 
						|
 | 
						|
        private String handleObject(Object obj) {
 | 
						|
            return obj == null? "": String.valueOf(obj);
 | 
						|
        }
 | 
						|
 | 
						|
        private String handleBigDecimal(BigDecimal decimal) {
 | 
						|
            return decimal == null? "": decimal.toString();
 | 
						|
        }
 | 
						|
 | 
						|
        private String handleLong(ResultSet rs, int columnIndex) throws SQLException {
 | 
						|
            long lv = rs.getLong(columnIndex);
 | 
						|
            return rs.wasNull()? "": Long.toString(lv);
 | 
						|
        }
 | 
						|
 | 
						|
        private String handleInteger(ResultSet rs, int columnIndex) throws SQLException {
 | 
						|
            int i = rs.getInt(columnIndex);
 | 
						|
            return rs.wasNull()? "": Integer.toString(i);
 | 
						|
        }
 | 
						|
 | 
						|
        private String handleDate(ResultSet rs, int columnIndex) throws SQLException {
 | 
						|
            java.sql.Date date = rs.getDate(columnIndex);
 | 
						|
            String value = null;
 | 
						|
            if (date != null) {
 | 
						|
                SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
 | 
						|
                value = dateFormat.format(date);
 | 
						|
            }
 | 
						|
            return value;
 | 
						|
        }
 | 
						|
 | 
						|
        private String handleTime(Time time) {
 | 
						|
            return time == null? null: time.toString();
 | 
						|
        }
 | 
						|
 | 
						|
        private String handleTimestamp(Timestamp timestamp) {
 | 
						|
            SimpleDateFormat timeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
 | 
						|
            return timestamp == null? null: timeFormat.format(timestamp);
 | 
						|
        }
 | 
						|
 | 
						|
        private String getColumnValue(ResultSet rs, int colType, int colIndex) throws SQLException,
 | 
						|
                IOException {
 | 
						|
            String value = "";
 | 
						|
            switch (colType) {
 | 
						|
            case Types.BIT:
 | 
						|
            case Types.JAVA_OBJECT:
 | 
						|
                value = handleObject(rs.getObject(colIndex));
 | 
						|
                break;
 | 
						|
            case Types.BOOLEAN:
 | 
						|
                boolean b = rs.getBoolean(colIndex);
 | 
						|
                value = Boolean.valueOf(b).toString();
 | 
						|
                break;
 | 
						|
            case NCLOB: // todo : use rs.getNClob
 | 
						|
            case Types.CLOB:
 | 
						|
                Clob c = rs.getClob(colIndex);
 | 
						|
                if (c != null) value = read(c);
 | 
						|
                break;
 | 
						|
            case Types.BIGINT:
 | 
						|
                value = handleLong(rs, colIndex);
 | 
						|
                break;
 | 
						|
            case Types.DECIMAL:
 | 
						|
            case Types.DOUBLE:
 | 
						|
            case Types.FLOAT:
 | 
						|
            case Types.REAL:
 | 
						|
            case Types.NUMERIC:
 | 
						|
                value = handleBigDecimal(rs.getBigDecimal(colIndex));
 | 
						|
                break;
 | 
						|
            case Types.INTEGER:
 | 
						|
            case Types.TINYINT:
 | 
						|
            case Types.SMALLINT:
 | 
						|
                value = handleInteger(rs, colIndex);
 | 
						|
                break;
 | 
						|
            case Types.DATE:
 | 
						|
                value = handleDate(rs, colIndex);
 | 
						|
                break;
 | 
						|
            case Types.TIME:
 | 
						|
                value = handleTime(rs.getTime(colIndex));
 | 
						|
                break;
 | 
						|
            case Types.TIMESTAMP:
 | 
						|
                value = handleTimestamp(rs.getTimestamp(colIndex));
 | 
						|
                break;
 | 
						|
            case NVARCHAR: // todo : use rs.getNString
 | 
						|
            case NCHAR: // todo : use rs.getNString
 | 
						|
            case LONGNVARCHAR: // todo : use rs.getNString
 | 
						|
            case Types.LONGVARCHAR:
 | 
						|
            case Types.VARCHAR:
 | 
						|
            case Types.CHAR:
 | 
						|
                value = rs.getString(colIndex);
 | 
						|
                break;
 | 
						|
            default:
 | 
						|
                value = "";
 | 
						|
            }
 | 
						|
            if (value == null) value = "";
 | 
						|
            return value;
 | 
						|
 | 
						|
        }
 | 
						|
 | 
						|
        private static String read(Clob c) throws SQLException, IOException {
 | 
						|
            StringBuilder sb = new StringBuilder((int)c.length());
 | 
						|
            Reader r = c.getCharacterStream();
 | 
						|
            char[] cbuf = new char[CLOBBUFFERSIZE];
 | 
						|
            int n;
 | 
						|
            while ((n = r.read(cbuf, 0, cbuf.length)) != -1) {
 | 
						|
                sb.append(cbuf, 0, n);
 | 
						|
            }
 | 
						|
            return sb.toString();
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    public static class CSVWriter implements Closeable {
 | 
						|
        public static final int INITIAL_STRING_SIZE = 128;
 | 
						|
 | 
						|
        public static final char DEFAULT_ESCAPE_CHARACTER = '"';
 | 
						|
 | 
						|
        public static final char DEFAULT_SEPARATOR = ',';
 | 
						|
 | 
						|
        public static final char DEFAULT_QUOTE_CHARACTER = '"';
 | 
						|
 | 
						|
        public static final char NO_QUOTE_CHARACTER = '\u0000';
 | 
						|
 | 
						|
        public static final char NO_ESCAPE_CHARACTER = '\u0000';
 | 
						|
 | 
						|
        public static final String DEFAULT_LINE_END = "\n";
 | 
						|
 | 
						|
        public static final StringBuilder quoteCsv(String s, char escapechar, char quotechar,
 | 
						|
                StringBuilder sb) {
 | 
						|
            if (sb == null) sb = new StringBuilder(INITIAL_STRING_SIZE);
 | 
						|
            for (int j = 0; j < s.length(); j++) {
 | 
						|
                char nextChar = s.charAt(j);
 | 
						|
                if (escapechar != NO_ESCAPE_CHARACTER && nextChar == quotechar) {
 | 
						|
                    sb.append(escapechar).append(nextChar);
 | 
						|
                } else if (escapechar != NO_ESCAPE_CHARACTER && nextChar == escapechar) {
 | 
						|
                    sb.append(escapechar).append(nextChar);
 | 
						|
                } else {
 | 
						|
                    sb.append(nextChar);
 | 
						|
                }
 | 
						|
            }
 | 
						|
            return sb;
 | 
						|
        }
 | 
						|
 | 
						|
        public static final String quoteCsv(String s) {
 | 
						|
            StringBuilder sb = new StringBuilder(INITIAL_STRING_SIZE);
 | 
						|
            sb.append(DEFAULT_QUOTE_CHARACTER);
 | 
						|
            quoteCsv(s, DEFAULT_ESCAPE_CHARACTER, DEFAULT_QUOTE_CHARACTER, sb);
 | 
						|
            sb.append(DEFAULT_QUOTE_CHARACTER);
 | 
						|
            return sb.toString();
 | 
						|
        }
 | 
						|
 | 
						|
        public Writer out;
 | 
						|
 | 
						|
        protected char separator;
 | 
						|
 | 
						|
        protected char quotechar;
 | 
						|
 | 
						|
        protected char escapechar;
 | 
						|
 | 
						|
        protected String lineEnd;
 | 
						|
 | 
						|
        private ResultSetHelper resultSetHelper = new ResultSetHelper();
 | 
						|
 | 
						|
        public CSVWriter(Writer writer) {
 | 
						|
            this(writer, DEFAULT_SEPARATOR);
 | 
						|
        }
 | 
						|
 | 
						|
        public CSVWriter(Writer writer, char separator) {
 | 
						|
            this(writer, separator, DEFAULT_QUOTE_CHARACTER);
 | 
						|
        }
 | 
						|
 | 
						|
        public CSVWriter(Writer writer, char separator, char quotechar) {
 | 
						|
            this(writer, separator, quotechar, DEFAULT_ESCAPE_CHARACTER);
 | 
						|
        }
 | 
						|
 | 
						|
        public CSVWriter(Writer writer, char separator, char quotechar, char escapechar) {
 | 
						|
            this(writer, separator, quotechar, escapechar, DEFAULT_LINE_END);
 | 
						|
        }
 | 
						|
 | 
						|
        public CSVWriter(Writer writer, char separator, char quotechar, String lineEnd) {
 | 
						|
            this(writer, separator, quotechar, DEFAULT_ESCAPE_CHARACTER, lineEnd);
 | 
						|
        }
 | 
						|
 | 
						|
        public CSVWriter(Writer writer, char separator, char quotechar, char escapechar,
 | 
						|
                String lineEnd) {
 | 
						|
            this.out = writer;
 | 
						|
            this.separator = separator;
 | 
						|
            this.quotechar = quotechar;
 | 
						|
            this.escapechar = escapechar;
 | 
						|
            this.lineEnd = lineEnd;
 | 
						|
        }
 | 
						|
 | 
						|
        public void writeAll(List<String[]> allLines) throws IOException {
 | 
						|
            for (String[] line : allLines) {
 | 
						|
                writeNext(line);
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        protected void writeColumnNames(ResultSet rs) throws SQLException, IOException {
 | 
						|
            writeNext(ResultSetHelper.getColumnNames(rs));
 | 
						|
        }
 | 
						|
 | 
						|
        public void writeAll(java.sql.ResultSet rs, boolean includeColumnNames)
 | 
						|
                throws SQLException, IOException {
 | 
						|
            if (includeColumnNames) writeColumnNames(rs);
 | 
						|
            while (rs.next()) {
 | 
						|
                writeNext(resultSetHelper.getColumnValues(rs));
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        public void writeNext(String[] nextLine) throws IOException {
 | 
						|
            if (nextLine == null) return;
 | 
						|
            StringBuilder sb = new StringBuilder(INITIAL_STRING_SIZE);
 | 
						|
            for (int i = 0; i < nextLine.length; i++) {
 | 
						|
                if (i != 0) sb.append(separator);
 | 
						|
                String nextElement = nextLine[i];
 | 
						|
                if (nextElement == null) continue;
 | 
						|
                if (quotechar != NO_QUOTE_CHARACTER) sb.append(quotechar);
 | 
						|
                sb.append(stringContainsSpecialCharacters(nextElement)? processLine(nextElement)
 | 
						|
                        : nextElement);
 | 
						|
                if (quotechar != NO_QUOTE_CHARACTER) sb.append(quotechar);
 | 
						|
            }
 | 
						|
            sb.append(lineEnd);
 | 
						|
            out.write(sb.toString());
 | 
						|
        }
 | 
						|
 | 
						|
        protected boolean stringContainsSpecialCharacters(String line) {
 | 
						|
            return line.indexOf(quotechar) != -1 || line.indexOf(escapechar) != -1;
 | 
						|
        }
 | 
						|
 | 
						|
        protected StringBuilder processLine(String nextElement) {
 | 
						|
            StringBuilder sb = new StringBuilder(INITIAL_STRING_SIZE);
 | 
						|
            for (int j = 0; j < nextElement.length(); j++) {
 | 
						|
                char nextChar = nextElement.charAt(j);
 | 
						|
                if (escapechar != NO_ESCAPE_CHARACTER && nextChar == quotechar) {
 | 
						|
                    sb.append(escapechar).append(nextChar);
 | 
						|
                } else if (escapechar != NO_ESCAPE_CHARACTER && nextChar == escapechar) {
 | 
						|
                    sb.append(escapechar).append(nextChar);
 | 
						|
                } else {
 | 
						|
                    sb.append(nextChar);
 | 
						|
                }
 | 
						|
            }
 | 
						|
            return sb;
 | 
						|
        }
 | 
						|
 | 
						|
        public void flush() throws IOException {
 | 
						|
            out.flush();
 | 
						|
        }
 | 
						|
 | 
						|
        public void close() throws IOException {
 | 
						|
            flush();
 | 
						|
            out.close();
 | 
						|
        }
 | 
						|
 | 
						|
        public void setResultSetHelper(ResultSetHelper resultSetHelper) {
 | 
						|
            this.resultSetHelper = resultSetHelper;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    public static class SqlResultSetHelper extends ResultSetHelper {
 | 
						|
        @Override
 | 
						|
        public String[] getColumnValues(ResultSet rs) throws SQLException, IOException {
 | 
						|
            List<String> values = new ArrayList<String>();
 | 
						|
            ResultSetMetaData metadata = rs.getMetaData();
 | 
						|
            int columnCount = metadata.getColumnCount();
 | 
						|
            for (int i = 0; i < columnCount; i++) {
 | 
						|
                values.add(getColumnValue(rs, metadata.getColumnType(i + 1), i + 1));
 | 
						|
            }
 | 
						|
            String[] valueArray = new String[values.size()];
 | 
						|
            return values.toArray(valueArray);
 | 
						|
        }
 | 
						|
 | 
						|
        private String getColumnValue(ResultSet rs, int colType, int colIndex) throws SQLException,
 | 
						|
                IOException {
 | 
						|
            String value = null;
 | 
						|
            switch (colType) {
 | 
						|
            case Types.BIT:
 | 
						|
            case Types.JAVA_OBJECT:
 | 
						|
                Object ov = rs.getObject(colIndex);
 | 
						|
                if (!rs.wasNull() && ov != null) value = String.valueOf(ov);
 | 
						|
                break;
 | 
						|
            case Types.BOOLEAN:
 | 
						|
                Boolean bv = rs.getBoolean(colIndex);
 | 
						|
                if (!rs.wasNull() && bv != null) value = Boolean.toString(bv);
 | 
						|
                break;
 | 
						|
            case NCLOB: // todo : use rs.getNClob
 | 
						|
            case Types.CLOB:
 | 
						|
                Clob cv = rs.getClob(colIndex);
 | 
						|
                if (!rs.wasNull() && cv != null) value = read(cv);
 | 
						|
                break;
 | 
						|
            case Types.BIGINT:
 | 
						|
                Long lv = rs.getLong(colIndex);
 | 
						|
                if (!rs.wasNull() && lv != null) value = Long.toString(lv);
 | 
						|
                break;
 | 
						|
            case Types.DECIMAL:
 | 
						|
            case Types.DOUBLE:
 | 
						|
            case Types.FLOAT:
 | 
						|
            case Types.REAL:
 | 
						|
            case Types.NUMERIC:
 | 
						|
                BigDecimal bdv = rs.getBigDecimal(colIndex);
 | 
						|
                if (!rs.wasNull() && bdv != null) value = bdv.toString();
 | 
						|
                break;
 | 
						|
            case Types.INTEGER:
 | 
						|
            case Types.TINYINT:
 | 
						|
            case Types.SMALLINT:
 | 
						|
                Integer iv = rs.getInt(colIndex);
 | 
						|
                if (!rs.wasNull() && iv != null) value = Integer.toString(iv);
 | 
						|
                break;
 | 
						|
            case Types.DATE:
 | 
						|
                Date dv = rs.getDate(colIndex);
 | 
						|
                if (!rs.wasNull() && dv != null) {
 | 
						|
                    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
 | 
						|
                    value = dateFormat.format(dv);
 | 
						|
                }
 | 
						|
                break;
 | 
						|
            case Types.TIME:
 | 
						|
                Time tv = rs.getTime(colIndex);
 | 
						|
                if (!rs.wasNull() && tv != null) value = tv.toString();
 | 
						|
                break;
 | 
						|
            case Types.TIMESTAMP:
 | 
						|
                Timestamp tsv = rs.getTimestamp(colIndex);
 | 
						|
                if (!rs.wasNull() && tsv != null) {
 | 
						|
                    SimpleDateFormat timestampFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
 | 
						|
                    value = timestampFormat.format(tsv);
 | 
						|
                }
 | 
						|
                break;
 | 
						|
            case NVARCHAR: // todo : use rs.getNString
 | 
						|
            case NCHAR: // todo : use rs.getNString
 | 
						|
            case LONGNVARCHAR: // todo : use rs.getNString
 | 
						|
            case Types.LONGVARCHAR:
 | 
						|
            case Types.VARCHAR:
 | 
						|
            case Types.CHAR:
 | 
						|
                value = rs.getString(colIndex);
 | 
						|
                break;
 | 
						|
            default:
 | 
						|
                value = "<unknown>";
 | 
						|
            }
 | 
						|
 | 
						|
            return value;
 | 
						|
        }
 | 
						|
 | 
						|
        private static final String read(Clob c) throws SQLException, IOException {
 | 
						|
            StringBuilder sb = new StringBuilder((int)c.length());
 | 
						|
            Reader r = c.getCharacterStream();
 | 
						|
            char[] cbuf = new char[CLOBBUFFERSIZE];
 | 
						|
            int n;
 | 
						|
            while ((n = r.read(cbuf, 0, cbuf.length)) != -1) {
 | 
						|
                sb.append(cbuf, 0, n);
 | 
						|
            }
 | 
						|
            return sb.toString();
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    public static class SqlCSVWriter extends CSVWriter {
 | 
						|
        public SqlCSVWriter(Writer writer) {
 | 
						|
            this(writer, DEFAULT_SEPARATOR);
 | 
						|
        }
 | 
						|
 | 
						|
        public SqlCSVWriter(Writer writer, char separator) {
 | 
						|
            this(writer, separator, DEFAULT_QUOTE_CHARACTER);
 | 
						|
        }
 | 
						|
 | 
						|
        public SqlCSVWriter(Writer writer, char separator, char quotechar) {
 | 
						|
            this(writer, separator, quotechar, DEFAULT_ESCAPE_CHARACTER);
 | 
						|
        }
 | 
						|
 | 
						|
        public SqlCSVWriter(Writer writer, char separator, char quotechar, char escapechar) {
 | 
						|
            this(writer, separator, quotechar, escapechar, DEFAULT_LINE_END);
 | 
						|
        }
 | 
						|
 | 
						|
        public SqlCSVWriter(Writer writer, char separator, char quotechar, String lineEnd) {
 | 
						|
            this(writer, separator, quotechar, DEFAULT_ESCAPE_CHARACTER, lineEnd);
 | 
						|
        }
 | 
						|
 | 
						|
        public SqlCSVWriter(Writer writer, char separator, char quotechar, char escapechar,
 | 
						|
                String lineEnd) {
 | 
						|
            super(writer, separator, quotechar, escapechar, lineEnd);
 | 
						|
            setResultSetHelper(new SqlResultSetHelper());
 | 
						|
        }
 | 
						|
 | 
						|
        @Override
 | 
						|
        public void writeNext(String[] nextLine) throws IOException {
 | 
						|
            if (nextLine == null) return;
 | 
						|
            StringBuilder sb = new StringBuilder(INITIAL_STRING_SIZE);
 | 
						|
            for (int i = 0; i < nextLine.length; i++) {
 | 
						|
                if (i != 0) sb.append(separator);
 | 
						|
 | 
						|
                String nextElement = nextLine[i];
 | 
						|
                if (nextElement != null) {
 | 
						|
                    if (quotechar != NO_QUOTE_CHARACTER) sb.append(quotechar);
 | 
						|
                    if (stringContainsSpecialCharacters(nextElement)) {
 | 
						|
                        sb.append(processLine(nextElement));
 | 
						|
                    } else {
 | 
						|
                        sb.append(nextElement);
 | 
						|
                    }
 | 
						|
                    if (quotechar != NO_QUOTE_CHARACTER) sb.append(quotechar);
 | 
						|
                } else {
 | 
						|
                    sb.append("NULL");
 | 
						|
                }
 | 
						|
            }
 | 
						|
            sb.append(lineEnd);
 | 
						|
            out.write(sb.toString());
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    // ------------------------------------------------------------------------
 | 
						|
    static class DelegateDriver implements Driver {
 | 
						|
        private Driver driver;
 | 
						|
 | 
						|
        DelegateDriver(Driver driver) {
 | 
						|
            this.driver = driver;
 | 
						|
        }
 | 
						|
 | 
						|
        public boolean acceptsURL(String u) throws SQLException {
 | 
						|
            return driver.acceptsURL(u);
 | 
						|
        }
 | 
						|
 | 
						|
        public Connection connect(String u, Properties p) throws SQLException {
 | 
						|
            return driver.connect(u, p);
 | 
						|
        }
 | 
						|
 | 
						|
        public int getMajorVersion() {
 | 
						|
            return driver.getMajorVersion();
 | 
						|
        }
 | 
						|
 | 
						|
        public int getMinorVersion() {
 | 
						|
            return driver.getMinorVersion();
 | 
						|
        }
 | 
						|
 | 
						|
        public DriverPropertyInfo[] getPropertyInfo(String u, Properties p) throws SQLException {
 | 
						|
            return driver.getPropertyInfo(u, p);
 | 
						|
        }
 | 
						|
 | 
						|
        public boolean jdbcCompliant() {
 | 
						|
            return driver.jdbcCompliant();
 | 
						|
        }
 | 
						|
 | 
						|
        public Logger getParentLogger() {
 | 
						|
            try {
 | 
						|
                return (Logger)driver.getClass().getMethod("getParentLogger").invoke(driver);
 | 
						|
            } catch (Exception e) {
 | 
						|
                Throwable t = e;
 | 
						|
                if (t instanceof InvocationTargetException) t = t.getCause();
 | 
						|
                throw new RuntimeException(t);
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    static final String[] SUPPORTED_DRIVERS = new String[] {
 | 
						|
            "com.mysql.jdbc.Driver",
 | 
						|
            "oracle.jdbc.OracleDriver",
 | 
						|
            "org.hsqldb.jdbcDriver",
 | 
						|
            "org.postgresql.Driver"};
 | 
						|
 | 
						|
    static final class Exit extends RuntimeException {
 | 
						|
        private static final long serialVersionUID = 1L;
 | 
						|
 | 
						|
        public Exit(int exitcode, String errorMsg) {
 | 
						|
            this.exitcode = exitcode;
 | 
						|
            this.errorMsg = errorMsg;
 | 
						|
        }
 | 
						|
 | 
						|
        public Exit(String errorMsg) {
 | 
						|
            this(1, errorMsg);
 | 
						|
        }
 | 
						|
 | 
						|
        public Exit(int exitcode) {
 | 
						|
            this(exitcode, null);
 | 
						|
        }
 | 
						|
 | 
						|
        public Exit() {
 | 
						|
            this(0, null);
 | 
						|
        }
 | 
						|
 | 
						|
        private int exitcode;
 | 
						|
 | 
						|
        public int getExitcode() {
 | 
						|
            return exitcode;
 | 
						|
        }
 | 
						|
 | 
						|
        private String errorMsg;
 | 
						|
 | 
						|
        public String getErrorMsg() {
 | 
						|
            return errorMsg;
 | 
						|
        }
 | 
						|
 | 
						|
        public void exit(String prefix) {
 | 
						|
            StringBuilder sb = new StringBuilder();
 | 
						|
            if (prefix != null) sb.append(prefix);
 | 
						|
            if (errorMsg != null) sb.append(errorMsg);
 | 
						|
            if (sb.length() > 0) {
 | 
						|
                System.err.println(sb.toString());
 | 
						|
                System.err.flush();
 | 
						|
            }
 | 
						|
            System.exit(exitcode);
 | 
						|
        }
 | 
						|
 | 
						|
        public void exit() {
 | 
						|
            if (exitcode == 0) exit(null);
 | 
						|
            else exit("ERROR: ");
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    static final String getArg(String[] args, int index, String errorMsg) {
 | 
						|
        if (args.length > index) return args[index];
 | 
						|
        if (errorMsg == null) return null;
 | 
						|
        throw new Exit(1, errorMsg);
 | 
						|
    }
 | 
						|
 | 
						|
    static final String getExceptionAndMessage(String msg, Throwable t) {
 | 
						|
        if (t == null) return msg;
 | 
						|
        StringBuilder sb = new StringBuilder();
 | 
						|
        if (msg != null) sb.append(msg);
 | 
						|
        sb.append(t.getClass().getName());
 | 
						|
        sb.append(": ");
 | 
						|
        sb.append(t.getMessage());
 | 
						|
        return sb.toString();
 | 
						|
    }
 | 
						|
 | 
						|
    static final String getSummary(String msg, Throwable t) {
 | 
						|
        if (t == null) return msg;
 | 
						|
        StringWriter sw = new StringWriter();
 | 
						|
        if (msg != null) sw.append(msg);
 | 
						|
        PrintWriter pw = new PrintWriter(sw);
 | 
						|
        t.printStackTrace(pw);
 | 
						|
        pw.flush();
 | 
						|
        return sw.toString();
 | 
						|
    }
 | 
						|
 | 
						|
    static final void logIgnoredError(Throwable t) {
 | 
						|
        log.info(getExceptionAndMessage("Erreur ignorée: ", t));
 | 
						|
        log.finer(getSummary(null, t));
 | 
						|
    }
 | 
						|
 | 
						|
    static final void println(String msg) {
 | 
						|
        System.out.println(msg);
 | 
						|
        System.out.flush();
 | 
						|
    }
 | 
						|
 | 
						|
    static final void die(String msg, Throwable t) {
 | 
						|
        if (msg != null) System.err.println(msg);
 | 
						|
        if (t != null) t.printStackTrace(System.err);
 | 
						|
        System.err.flush();
 | 
						|
        System.exit(1);
 | 
						|
    }
 | 
						|
 | 
						|
    static final boolean strIsempty(String str) {
 | 
						|
        return str == null || str.length() == 0;
 | 
						|
    }
 | 
						|
 | 
						|
    static final boolean strEquals(String s1, String s2, boolean ignoreCase) {
 | 
						|
        if (ignoreCase) return s1 == s2 || (s1 != null && s1.equalsIgnoreCase(s2));
 | 
						|
        else return s1 == s2 || (s1 != null && s1.equals(s2));
 | 
						|
    }
 | 
						|
 | 
						|
    static final boolean strEquals(String[] a1, String[] a2, boolean ignoreCase) {
 | 
						|
        if (a1 == null) return a2 == null;
 | 
						|
        else if (a2 == null) return false;
 | 
						|
        if (a1.length != a2.length) return false;
 | 
						|
        for (int i = 0; i < a1.length; i++) {
 | 
						|
            if (!strEquals(a1[i], a2[i], ignoreCase)) return false;
 | 
						|
        }
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    static final boolean strEquals(String s1, String s2) {
 | 
						|
        return strEquals(s1, s2, false);
 | 
						|
    }
 | 
						|
 | 
						|
    static final String strNotnull(String str) {
 | 
						|
        return str == null? "": str;
 | 
						|
    }
 | 
						|
 | 
						|
    static final String strSubstr(String str, int start, int end) {
 | 
						|
        if (str == null) return null;
 | 
						|
 | 
						|
        int l = str.length();
 | 
						|
        if (l > 0) {
 | 
						|
            while (start < 0)
 | 
						|
                start += l;
 | 
						|
            while (end < 0)
 | 
						|
                end += l;
 | 
						|
        } else {
 | 
						|
            if (start < 0) start = 0;
 | 
						|
            if (end < 0) end = 0;
 | 
						|
        }
 | 
						|
        if (start >= l || start >= end) return "";
 | 
						|
        if (end >= l + 1) end = l;
 | 
						|
 | 
						|
        return str.substring(start, end);
 | 
						|
    }
 | 
						|
 | 
						|
    static final String strSubstr(String str, int start) {
 | 
						|
        if (str == null) return null;
 | 
						|
        return strSubstr(str, start, str.length());
 | 
						|
    }
 | 
						|
 | 
						|
    static void close(InputStream is) {
 | 
						|
        try {
 | 
						|
            if (is != null) is.close();
 | 
						|
        } catch (IOException e) {
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    // static void close(OutputStream os) {
 | 
						|
    // try {
 | 
						|
    // if (os != null) os.close();
 | 
						|
    // } catch (IOException e) {
 | 
						|
    // }
 | 
						|
    // }
 | 
						|
 | 
						|
    static void close(Reader r) {
 | 
						|
        try {
 | 
						|
            if (r != null) r.close();
 | 
						|
        } catch (IOException e) {
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    static void close(Writer w) {
 | 
						|
        try {
 | 
						|
            if (w != null) w.close();
 | 
						|
        } catch (IOException e) {
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    static void close(CSVWriter csv, String output) {
 | 
						|
        try {
 | 
						|
            if (csv != null && output != null) csv.close();
 | 
						|
        } catch (IOException e) {
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    static void close(Connection conn) {
 | 
						|
        try {
 | 
						|
            if (conn != null) conn.close();
 | 
						|
        } catch (SQLException e) {
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    static void close(PreparedStatement ps) {
 | 
						|
        try {
 | 
						|
            if (ps != null) ps.close();
 | 
						|
        } catch (SQLException e) {
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    static void close(ResultSet rs) {
 | 
						|
        try {
 | 
						|
            if (rs != null) rs.close();
 | 
						|
        } catch (SQLException e) {
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    static void rollback(Connection conn) {
 | 
						|
        try {
 | 
						|
            if (!conn.getAutoCommit()) conn.rollback();
 | 
						|
        } catch (SQLException e) {
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    static final Pattern RE_COMMENT = Pattern.compile("--|#|//");
 | 
						|
 | 
						|
    static String nextLine(BufferedReader inf) throws IOException {
 | 
						|
        while (true) {
 | 
						|
            String line = inf.readLine();
 | 
						|
            if (line == null) return null;
 | 
						|
            line = line.trim();
 | 
						|
            if (!line.equals("") && !RE_COMMENT.matcher(line).lookingAt()) return line;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    static final Pattern RE_CREATE_STMT = Pattern
 | 
						|
            .compile("(?i)create\\s+(?:or\\s+replace)?(?:procedure|trigger|function|package)");
 | 
						|
 | 
						|
    static final Pattern RE_SEPARATOR = Pattern.compile(";$");
 | 
						|
 | 
						|
    static String nextStatement(BufferedReader inf) throws IOException {
 | 
						|
        String line = nextLine(inf);
 | 
						|
        if (line == null) return null;
 | 
						|
 | 
						|
        StringBuilder sb = new StringBuilder();
 | 
						|
        boolean first = true;
 | 
						|
        if (RE_CREATE_STMT.matcher(line).lookingAt()) {
 | 
						|
            // Ici, lire jusqu'à une ligne contenant simplement '/'
 | 
						|
            do {
 | 
						|
                if (line.equals("/")) break;
 | 
						|
                if (first) first = false;
 | 
						|
                else sb.append("\n");
 | 
						|
                sb.append(line);
 | 
						|
                line = nextLine(inf);
 | 
						|
            } while (line != null);
 | 
						|
        } else {
 | 
						|
            // Ici, lire jusqu'à une ligne se *terminant* par ';'
 | 
						|
            do {
 | 
						|
                if (first) first = false;
 | 
						|
                else sb.append(" ");
 | 
						|
                boolean lastLine = line.endsWith(";");
 | 
						|
                sb.append(RE_SEPARATOR.matcher(line).replaceFirst(""));
 | 
						|
                if (lastLine) break;
 | 
						|
                line = nextLine(inf);
 | 
						|
            } while (line != null);
 | 
						|
        }
 | 
						|
 | 
						|
        return sb.toString();
 | 
						|
    }
 | 
						|
 | 
						|
    static PreparedStatement getPreparedStatement(String query, Object[] args, Connection conn)
 | 
						|
            throws SQLException {
 | 
						|
        PreparedStatement ps = conn.prepareStatement(query);
 | 
						|
        if (args != null) {
 | 
						|
            for (int i = 0; i < args.length; i++) {
 | 
						|
                Object arg = args[i];
 | 
						|
                if (arg instanceof java.util.Date && !(arg instanceof Date)
 | 
						|
                        && !(arg instanceof Time) && !(arg instanceof Timestamp)) {
 | 
						|
                    // corriger les instances de java.util.Date en java.sql.Timestamp
 | 
						|
                    if (arg == null || arg instanceof Timestamp) arg = (Timestamp)arg;
 | 
						|
                    else arg = new Timestamp(((java.util.Date)arg).getTime());
 | 
						|
                }
 | 
						|
                ps.setObject(i + 1, arg);
 | 
						|
            }
 | 
						|
        }
 | 
						|
        return ps;
 | 
						|
    }
 | 
						|
 | 
						|
    SqlCSVWriter getCSVWriter(String output, boolean append) throws FileNotFoundException {
 | 
						|
        Writer outf;
 | 
						|
        if (output != null) {
 | 
						|
            outf = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(output, append),
 | 
						|
                    UTF8));
 | 
						|
        } else {
 | 
						|
            outf = new OutputStreamWriter(System.out);
 | 
						|
        }
 | 
						|
        return new SqlCSVWriter(outf);
 | 
						|
    }
 | 
						|
 | 
						|
    static class Options {
 | 
						|
        public Options(boolean ignoreIoError, boolean ignoreAnyError, boolean noHeaders,
 | 
						|
                boolean append, boolean sameOutput, boolean forceHeaders, boolean outputUc) {
 | 
						|
            this.ignoreIoErrors = ignoreIoError;
 | 
						|
            this.ignoreAnyErrors = ignoreIoError;
 | 
						|
            this.noHeaders = noHeaders;
 | 
						|
            this.append = append;
 | 
						|
            this.sameOutput = sameOutput;
 | 
						|
            this.forceHeaders = forceHeaders;
 | 
						|
            this.outputUc = outputUc;
 | 
						|
        }
 | 
						|
 | 
						|
        public Options() {
 | 
						|
            this(false, false, false, false, false, false, false);
 | 
						|
        }
 | 
						|
 | 
						|
        public boolean ignoreIoErrors;
 | 
						|
 | 
						|
        public boolean ignoreAnyErrors;
 | 
						|
 | 
						|
        public boolean noHeaders;
 | 
						|
 | 
						|
        public boolean append;
 | 
						|
 | 
						|
        public boolean sameOutput;
 | 
						|
 | 
						|
        public boolean forceHeaders;
 | 
						|
 | 
						|
        public boolean outputUc;
 | 
						|
    }
 | 
						|
 | 
						|
    static final String[] UC_FIELDS = new String[] {"updateCount"};
 | 
						|
 | 
						|
    static final Pattern RE_NAME_EXT = Pattern.compile("(.+?)(?:(\\d+))?(?:(\\.[^.]+))?");
 | 
						|
 | 
						|
    void executeQueries(Connection conn, Object[] args, ArrayList<BufferedReader> infs,
 | 
						|
            ArrayList<String> outputs, Options o) throws IOException, SQLException {
 | 
						|
        int stcount = 0;
 | 
						|
        Iterator<String> outputIt = outputs.iterator();
 | 
						|
        String output = null, prevOutput = null, actualOutput = null;
 | 
						|
        String[] fields = null, prevFields = null;
 | 
						|
        boolean firstWrite = true;
 | 
						|
        for (BufferedReader inf : infs) {
 | 
						|
            try {
 | 
						|
                while (true) {
 | 
						|
                    String statement = nextStatement(inf);
 | 
						|
                    if (statement == null) break;
 | 
						|
                    stcount++;
 | 
						|
 | 
						|
                    log.finer(statement);
 | 
						|
                    try {
 | 
						|
                        PreparedStatement ps = getPreparedStatement(statement, args, conn);
 | 
						|
                        try {
 | 
						|
                            boolean rt = ps.execute();
 | 
						|
                            while (true) {
 | 
						|
                                int uc = 0;
 | 
						|
                                boolean writeOutput;
 | 
						|
                                if (rt) {
 | 
						|
                                    writeOutput = true;
 | 
						|
                                } else {
 | 
						|
                                    uc = ps.getUpdateCount();
 | 
						|
                                    if (uc == -1) break;
 | 
						|
                                    writeOutput = o.outputUc;
 | 
						|
                                }
 | 
						|
 | 
						|
                                SqlCSVWriter csv = null;
 | 
						|
                                prevOutput = output;
 | 
						|
                                prevFields = fields;
 | 
						|
                                boolean sameOutput = false, append = false;
 | 
						|
                                if (writeOutput) {
 | 
						|
                                    if (outputIt.hasNext()) output = outputIt.next();
 | 
						|
                                    if (!strEquals(output, prevOutput)) {
 | 
						|
                                        sameOutput = false;
 | 
						|
                                        firstWrite = true;
 | 
						|
                                        actualOutput = output;
 | 
						|
                                    } else if (o.sameOutput) {
 | 
						|
                                        sameOutput = true;
 | 
						|
                                        append = true;
 | 
						|
                                    } else if (output != null) {
 | 
						|
                                        String dir, basename, sindex, ext;
 | 
						|
                                        int index = 0;
 | 
						|
                                        sameOutput = true;
 | 
						|
                                        File file = new File(actualOutput);
 | 
						|
                                        dir = file.getParent();
 | 
						|
                                        Matcher m = RE_NAME_EXT.matcher(file.getName());
 | 
						|
                                        if (m.matches()) {
 | 
						|
                                            basename = m.group(1);
 | 
						|
                                            sindex = m.group(2);
 | 
						|
                                            ext = m.group(3);
 | 
						|
                                            if (sindex != null) index = Integer.valueOf(sindex);
 | 
						|
                                            index++;
 | 
						|
 | 
						|
                                            StringBuilder sb = new StringBuilder();
 | 
						|
                                            if (dir != null) {
 | 
						|
                                                sb.append(dir);
 | 
						|
                                                sb.append("/");
 | 
						|
                                            }
 | 
						|
                                            sb.append(basename);
 | 
						|
                                            sb.append(index);
 | 
						|
                                            if (ext != null) sb.append(ext);
 | 
						|
                                            actualOutput = sb.toString();
 | 
						|
                                            firstWrite = true;
 | 
						|
                                            sameOutput = false;
 | 
						|
                                        }
 | 
						|
                                    }
 | 
						|
                                }
 | 
						|
 | 
						|
                                log.fine("stmt#" + stcount);
 | 
						|
                                ResultSet rs = null;
 | 
						|
                                if (rt) {
 | 
						|
                                    rs = ps.getResultSet();
 | 
						|
                                    fields = ResultSetHelper.getColumnNames(rs);
 | 
						|
                                } else if (o.outputUc) {
 | 
						|
                                    fields = UC_FIELDS;
 | 
						|
                                }
 | 
						|
                                boolean sameFields = strEquals(fields, prevFields, true);
 | 
						|
                                boolean writeHeaders = !o.noHeaders
 | 
						|
                                        && !(sameFields && sameOutput && !o.forceHeaders);
 | 
						|
                                if (writeOutput) {
 | 
						|
                                    csv = getCSVWriter(actualOutput, append | o.append);
 | 
						|
                                    if (sameOutput && !firstWrite
 | 
						|
                                            && (!sameFields || o.forceHeaders)) {
 | 
						|
                                        csv.out.write("\n");
 | 
						|
                                    }
 | 
						|
                                    try {
 | 
						|
                                        if (rt) {
 | 
						|
                                            csv.writeAll(rs, writeHeaders);
 | 
						|
                                        } else {
 | 
						|
                                            if (writeHeaders) csv.writeNext(UC_FIELDS);
 | 
						|
                                            csv.writeNext(new String[] {String.valueOf(uc)});
 | 
						|
                                        }
 | 
						|
                                        csv.flush();
 | 
						|
                                    } finally {
 | 
						|
                                        close(csv, actualOutput);
 | 
						|
                                        close(rs);
 | 
						|
                                    }
 | 
						|
                                }
 | 
						|
                                firstWrite = false;
 | 
						|
                                rt = ps.getMoreResults();
 | 
						|
                            }
 | 
						|
                        } finally {
 | 
						|
                            close(ps);
 | 
						|
                        }
 | 
						|
                    } catch (SQLException e) {
 | 
						|
                        if (o.ignoreAnyErrors) {
 | 
						|
                            logIgnoredError(e);
 | 
						|
                        } else {
 | 
						|
                            rollback(conn);
 | 
						|
                            throw e;
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            } catch (IOException e) {
 | 
						|
                if (o.ignoreIoErrors) {
 | 
						|
                    logIgnoredError(e);
 | 
						|
                } else {
 | 
						|
                    rollback(conn);
 | 
						|
                    throw e;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
        if (!conn.getAutoCommit()) conn.commit();
 | 
						|
    }
 | 
						|
 | 
						|
    static final Pattern RE_URL_PROP = Pattern.compile("(.+)\\.url$");
 | 
						|
 | 
						|
    void run(String[] args) throws Exception {
 | 
						|
        if (args.length == 1 && strEquals(args[0], "--help")) {
 | 
						|
            println("USAGE:" //
 | 
						|
                    + "\n    "
 | 
						|
                    + CLASS_NAME
 | 
						|
                    + " [query]"
 | 
						|
                    + "\n\nquery   est la requête SQL à exécuter. Si query n'est pas spécifiée ou si elle"
 | 
						|
                    + "\n        vaut '-', la requête SQL est lue sur l'entrée standard, ou depuis un"
 | 
						|
                    + "\n        fichier si l'option -f est spécifiée."
 | 
						|
                    + "\n\nDEMARRAGE"
 | 
						|
                    + "\n\nAu démarrage, les répertoires de configuration (utilisateur ~/.sqlcsv et système"
 | 
						|
                    + "\n/etc/sqlcsv) sont analysés. Les fichiers *.jar situés dans ces répertoires sont"
 | 
						|
                    + "\najoutés au CLASSPATH. La présence de certains fichiers est testée pour activer"
 | 
						|
                    + "\néventuellement les logs détaillés."
 | 
						|
                    + "\n\nOPTIONS"
 | 
						|
                    + "\n    -C, --config CONFIG"
 | 
						|
                    + "\n        Prendre les informations de connexion depuis le fichier de propriété"
 | 
						|
                    + "\n        spécifié. Pour l'identifiant CONN, la propriété 'CONN.url' doit exister"
 | 
						|
                    + "\n        dans ce fichier avec la valeur de l'url jdbc de connexion. De plus, les"
 | 
						|
                    + "\n        propriétés 'CONN.user' et 'CONN.password' contiennent respectivement si"
 | 
						|
                    + "\n        nécessaire le nom et le mot de passe de connexion. La propriété"
 | 
						|
                    + "\n        'loglevel', si elle existe, est utilisée pour configurer le niveau"
 | 
						|
                    + "\n        d'affichage des logs, comme avec l'option --loglevel"
 | 
						|
                    + "\n        Si cette option n'est pas spécifiée, un fichier nommé sqlcsv.properties"
 | 
						|
                    + "\n        est recherché dans l'ordre: dans le répertoire courant, dans le"
 | 
						|
                    + "\n        répertoire de configuration utilisateur, puis dans le répertoire de"
 | 
						|
                    + "\n        configuration système. Si le fichier est trouvé, il est chargé"
 | 
						|
                    + "\n        automatiquement."
 | 
						|
                    + "\n    -l, --conn CONN"
 | 
						|
                    + "\n        Spécifier l'identifiant (ou l'url) de connexion. Cette information est"
 | 
						|
                    + "\n        obligatoire. Si cette option n'est pas fournie, il faut spécifier un"
 | 
						|
                    + "\n        fichier de configuration avec l'option -C dans lequel *une seule*"
 | 
						|
                    + "\n        propriété 'CONN.url' est définie."
 | 
						|
                    + "\n    -u, --user USER"
 | 
						|
                    + "\n    -p, --password PASSWORD"
 | 
						|
                    + "\n        Spécifier un nom de connexion et un mot de passe si l'url ne le fournit"
 | 
						|
                    + "\n        pas. Ces valeurs ont la priorité sur les valeurs éventuellement déjà"
 | 
						|
                    + "\n        présentes dans le fichier de propriété."
 | 
						|
                    + "\n    -f, --input INPUT"
 | 
						|
                    + "\n        Lire la requête depuis le fichier INPUT au lieu de la lire depuis la"
 | 
						|
                    + "\n        ligne de commande ou l'entrée standard. Ne pas spécifier cette option ou"
 | 
						|
                    + "\n        utiliser '-' pour lire depuis l'entrée standard. Cette option est"
 | 
						|
                    + "\n        ignorée si la requête est fournie sur la ligne de commande."
 | 
						|
                    + "\n    -o, --output OUTPUT"
 | 
						|
                    + "\n        Ecrire le résultat dans le fichier OUTPUT. Utiliser '-' pour spécifier"
 | 
						|
                    + "\n        la sortie standard (c'est la valeur par défaut). S'il y a plusieurs"
 | 
						|
                    + "\n        requêtes et que le fichier de sortie n'est pas la sortie standard,"
 | 
						|
                    + "\n        ajouter un numéro incrémental au nom du fichier en sortie pour chaque"
 | 
						|
                    + "\n        requête. Sinon, il est possible de spécifier plusieurs fois cette option"
 | 
						|
                    + "\n        pour nommer les fichiers correspondant à chaque requête."
 | 
						|
                    + "\n    -t, --autocommit"
 | 
						|
                    + "\n        Activer le mode autocommit"
 | 
						|
                    + "\n    -c, --ignore-io-error"
 | 
						|
                    + "\n        Continuer le traitement même en cas d'erreur du système de fichiers."
 | 
						|
                    + "\n        Cependant le traitement s'arrête et la transaction est annulée si une"
 | 
						|
                    + "\n        autre erreur se produit."
 | 
						|
                    + "\n    -y, --ignore-any-error"
 | 
						|
                    + "\n        Continuer le traitement même en cas d'erreur quelconque."
 | 
						|
                    + "\n    -n, --no-headers"
 | 
						|
                    + "\n        Ne JAMAIS inclure les en-têtes dans la sortie, même avec l'option -h"
 | 
						|
                    + "\n    -a, --append"
 | 
						|
                    + "\n        Ajouter le résultat au fichier OUTPUT au lieu de l'écraser."
 | 
						|
                    + "\n    -A, --auto-na"
 | 
						|
                    + "\n        Activer les option -n -a si le fichier OUTPUT existe et qu'il est non"
 | 
						|
                    + "\n        vide. Le test n'est effectué que pour le premier fichier spécifié."
 | 
						|
                    + "\n    -s, --same-output"
 | 
						|
                    + "\n        Utiliser le même fichier pour écrire le résultat de toutes les requêtes."
 | 
						|
                    + "\n        Normalement, un numéro incrémental est ajouté au fichier en sortie si"
 | 
						|
                    + "\n        plusieurs requêtes sont spécifiées. Si les en-têtes sont les mêmes,"
 | 
						|
                    + "\n        ajouter le résultat au fichier directement à la suite. Sinon, sauter une"
 | 
						|
                    + "\n        ligne blanche et afficher les nouveaux en-têtes."
 | 
						|
                    + "\n    -h, --force-headers"
 | 
						|
                    + "\n        En cas d'écriture du résultat de plusieurs requêtes dans un même"
 | 
						|
                    + "\n        fichier, ne pas tenter de concaténer les résultats même si les en-têtes"
 | 
						|
                    + "\n        sont les mêmes."
 | 
						|
                    + "\n    --uc-output"
 | 
						|
                    + "\n        Ajouter dans la sortie les résultat de toutes les requêtes, pas"
 | 
						|
                    + "\n        seulement celles de type DQML"
 | 
						|
                    + "\n    --loglevel LOGLEVEL"
 | 
						|
                    + "\n        Spécifier le niveau de logs à afficher. Les valeurs valides sont à"
 | 
						|
                    + "\n        choisir parmi ALL, FINEST, FINER, FINE, CONFIG, INFO, WARNING, ERROR"
 | 
						|
                    + "\n        La présence de certains fichiers dans les répertoires de configuration"
 | 
						|
                    + "\n        utilisateur ou système configure les logs avant que les options de la"
 | 
						|
                    + "\n        ligne de commande ne soient analysés: un fichier DEBUG fait démarrer"
 | 
						|
                    + "\n        l'application avec le niveau de log ALL ce qui permet de voir les logs"
 | 
						|
                    + "\n        concernant le chargement des jar. Un fichier SQL_DEBUG permet d'activer"
 | 
						|
                    + "\n        la trace de DriverManager. Exemple:"
 | 
						|
                    + "\n            mkdir -p ~/.sqlcsv && touch ~/.sqlcsv/{DEBUG,SQL_DEBUG}");
 | 
						|
            return;
 | 
						|
        }
 | 
						|
 | 
						|
        String config = null, connid = null, user = null, password = null;
 | 
						|
        Options o = new Options();
 | 
						|
        boolean autocommit = false, autoNa = false;
 | 
						|
        String loglevel = null;
 | 
						|
        ArrayList<String> inputs = new ArrayList<String>();
 | 
						|
        ArrayList<String> outputs = new ArrayList<String>();
 | 
						|
        ArrayList<String> remainArgs = new ArrayList<String>();
 | 
						|
        int i = 0, max = args.length;
 | 
						|
        while (i < max) {
 | 
						|
            String arg = args[i];
 | 
						|
            if (arg.equals("-C") || arg.equals("--config")) {
 | 
						|
                config = getArg(args, ++i, "Vous devez spécifier le fichier de configuration");
 | 
						|
            } else if (arg.equals("-l") || arg.equals("--conn")) {
 | 
						|
                connid = getArg(args, ++i, "Vous devez spécifier l'identifiant de connexion");
 | 
						|
            } else if (arg.equals("-u") || arg.equals("--user")) {
 | 
						|
                user = getArg(args, ++i, "Vous devez spécifier l'utilisateur de connexion");
 | 
						|
            } else if (arg.equals("-p") || arg.equals("--password")) {
 | 
						|
                password = getArg(args, ++i, "Vous devez spécifier l'utilisateur de connexion");
 | 
						|
            } else if (arg.equals("-f") || arg.equals("--input")) {
 | 
						|
                String input = getArg(args, ++i, "Vous devez spécifier le fichier en entrée");
 | 
						|
                if (strEquals(input, "-") || strEquals(input, "/dev/stdin")) input = null;
 | 
						|
                inputs.add(input);
 | 
						|
            } else if (arg.equals("-o") || arg.equals("--output")) {
 | 
						|
                String output = getArg(args, ++i, "Vous devez spécifier le fichier en sortie");
 | 
						|
                if (strEquals(output, "-") || strEquals(output, "/dev/stdout")) output = null;
 | 
						|
                outputs.add(output);
 | 
						|
            } else if (arg.equals("-t") || arg.equals("--autocommit")) {
 | 
						|
                autocommit = true;
 | 
						|
            } else if (arg.equals("-c") || arg.equals("--ignore-io-error")) {
 | 
						|
                o.ignoreIoErrors = true;
 | 
						|
            } else if (arg.equals("-y") || arg.equals("--ignore-any-error")) {
 | 
						|
                o.ignoreAnyErrors = true;
 | 
						|
            } else if (arg.equals("-n") || arg.equals("--no-headers")) {
 | 
						|
                o.noHeaders = true;
 | 
						|
            } else if (arg.equals("-a") || arg.equals("--append")) {
 | 
						|
                o.append = true;
 | 
						|
            } else if (arg.equals("-A") || arg.equals("--auto-na")) {
 | 
						|
                autoNa = true;
 | 
						|
            } else if (arg.equals("-s") || arg.equals("--same-output")) {
 | 
						|
                o.sameOutput = true;
 | 
						|
            } else if (arg.equals("-h") || arg.equals("--force-headers")) {
 | 
						|
                o.forceHeaders = true;
 | 
						|
            } else if (arg.equals("--uc-output")) {
 | 
						|
                o.outputUc = true;
 | 
						|
            } else if (arg.equals("--loglevel")) {
 | 
						|
                loglevel = getArg(args, ++i, "Vous devez spécifier le niveau de logs");
 | 
						|
            } else if (arg.equals("--")) {
 | 
						|
                i++;
 | 
						|
                break;
 | 
						|
            } else {
 | 
						|
                remainArgs.add(arg);
 | 
						|
            }
 | 
						|
            i++;
 | 
						|
        }
 | 
						|
        args = remainArgs.toArray(new String[0]);
 | 
						|
 | 
						|
        if (loglevel != null) {
 | 
						|
            log.setLevel(Level.parse(loglevel.toUpperCase()));
 | 
						|
        }
 | 
						|
 | 
						|
        // Charger les propriétés
 | 
						|
        Properties props = null;
 | 
						|
        if (config == null && new File(DEFAULT_CONFIG).exists()) {
 | 
						|
            // essayer depuis le répertoire courant
 | 
						|
            config = DEFAULT_CONFIG;
 | 
						|
        }
 | 
						|
        if (config == null && new File(USER_CONFIG).exists()) {
 | 
						|
            // puis dans le répertoire de configuration utilisateur
 | 
						|
            config = USER_CONFIG;
 | 
						|
        }
 | 
						|
        if (config == null && new File(SYSTEM_CONFIG).exists()) {
 | 
						|
            // puis dans le répertoire de configuration système
 | 
						|
            config = SYSTEM_CONFIG;
 | 
						|
        }
 | 
						|
        if (config != null) {
 | 
						|
            log.config("Chargement des propriétés de " + config);
 | 
						|
            props = new Properties();
 | 
						|
            FileInputStream inf = null;
 | 
						|
            try {
 | 
						|
                inf = new FileInputStream(config);
 | 
						|
                props.load(inf);
 | 
						|
            } catch (FileNotFoundException e) {
 | 
						|
                throw new Exit(config + ": Fichier introuvable");
 | 
						|
            } finally {
 | 
						|
                close(inf);
 | 
						|
            }
 | 
						|
        }
 | 
						|
        if (props != null) {
 | 
						|
            String loglevelKey = "loglevel";
 | 
						|
            if (props.containsKey(loglevelKey)) {
 | 
						|
                loglevel = props.getProperty(loglevelKey);
 | 
						|
                log.setLevel(Level.parse(loglevel.toUpperCase()));
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        String jdbcUrl = null;
 | 
						|
        if (connid == null && props != null) {
 | 
						|
            // Essayer de deviner connid en parcourant les propriétés de props
 | 
						|
            @SuppressWarnings("unchecked")
 | 
						|
            Enumeration<String> en = (Enumeration<String>)props.propertyNames();
 | 
						|
            int count = 0;
 | 
						|
            while (en.hasMoreElements()) {
 | 
						|
                String propertyName = en.nextElement();
 | 
						|
                Matcher m = RE_URL_PROP.matcher(propertyName);
 | 
						|
                if (m.matches()) {
 | 
						|
                    connid = m.group(1);
 | 
						|
                    count++;
 | 
						|
                }
 | 
						|
            }
 | 
						|
            if (count > 1) {
 | 
						|
                // Si plusieurs configurations sont trouvées, ne pas en sélectionner une par
 | 
						|
                // défaut
 | 
						|
                connid = null;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        if (connid != null) {
 | 
						|
            if (props != null) {
 | 
						|
                String jdbcUrlKey = connid + ".url";
 | 
						|
                if (props.containsKey(jdbcUrlKey)) jdbcUrl = props.getProperty(jdbcUrlKey);
 | 
						|
                String userKey = connid + ".user";
 | 
						|
                if (props.containsKey(userKey)) user = props.getProperty(userKey);
 | 
						|
                String passwordKey = connid + ".password";
 | 
						|
                if (props.containsKey(passwordKey)) password = props.getProperty(passwordKey);
 | 
						|
            } else {
 | 
						|
                jdbcUrl = connid;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        if (jdbcUrl == null) throw new Exit("Vous devez spécifier l'url de connexion");
 | 
						|
 | 
						|
        // Ouvrir les fichiers en entrée
 | 
						|
        ArrayList<BufferedReader> infs = new ArrayList<BufferedReader>();
 | 
						|
        boolean parseInputs = true;
 | 
						|
        if (args.length > 0) {
 | 
						|
            String query = args[0];
 | 
						|
            if (!strEquals(query, "-")) {
 | 
						|
                infs.add(new BufferedReader(new StringReader(query)));
 | 
						|
                parseInputs = false;
 | 
						|
            }
 | 
						|
            // XXX analyser les arguments à transmettre à la requête
 | 
						|
        }
 | 
						|
        if (parseInputs) {
 | 
						|
            if (inputs.size() == 0) inputs.add(null);
 | 
						|
            BufferedReader inf;
 | 
						|
            for (String input : inputs) {
 | 
						|
                if (input == null) {
 | 
						|
                    inf = new BufferedReader(new InputStreamReader(System.in, UTF8));
 | 
						|
                } else {
 | 
						|
                    inf = new BufferedReader(
 | 
						|
                            new InputStreamReader(new FileInputStream(input), UTF8));
 | 
						|
                }
 | 
						|
                infs.add(inf);
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        // Préparer la liste des fichiers en sortie
 | 
						|
        if (outputs.size() == 0) outputs.add(null);
 | 
						|
        String output = outputs.get(0);
 | 
						|
        if (autoNa && output != null) {
 | 
						|
            if (new File(output).exists()) {
 | 
						|
                o.noHeaders = true;
 | 
						|
                o.append = true;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        // Ouvrir la connexion
 | 
						|
        log.config("Connexion à " + jdbcUrl);
 | 
						|
        Connection conn;
 | 
						|
        if (user == null && password == null) conn = DriverManager.getConnection(jdbcUrl);
 | 
						|
        else conn = DriverManager.getConnection(jdbcUrl, user, password);
 | 
						|
        conn.setAutoCommit(autocommit);
 | 
						|
 | 
						|
        // Exécuter les requêtes
 | 
						|
        try {
 | 
						|
            executeQueries(conn, null, infs, outputs, o);
 | 
						|
        } finally {
 | 
						|
            close(conn);
 | 
						|
            for (BufferedReader inf : infs) {
 | 
						|
                close(inf);
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    static final FilenameFilter JAR_FILTER = new FilenameFilter() {
 | 
						|
        public boolean accept(File dir, String name) {
 | 
						|
            return name.endsWith(".jar");
 | 
						|
        }
 | 
						|
    };
 | 
						|
 | 
						|
    static final boolean findJars(File confdir, ArrayList<URL> urls) {
 | 
						|
        if (!confdir.isDirectory()) return false;
 | 
						|
        log.config("Analyse des jars de " + confdir);
 | 
						|
        boolean foundJar = false;
 | 
						|
        for (File file : confdir.listFiles(JAR_FILTER)) {
 | 
						|
            try {
 | 
						|
                log.config("Ajout de " + file);
 | 
						|
                urls.add(file.toURI().toURL());
 | 
						|
                foundJar = true;
 | 
						|
            } catch (MalformedURLException e) {
 | 
						|
            }
 | 
						|
        }
 | 
						|
        return foundJar;
 | 
						|
    }
 | 
						|
 | 
						|
    public static void main(String[] args) throws Exception {
 | 
						|
        if (new File(USER_CONFDIR + "/DEBUG").exists()
 | 
						|
                || new File(SYSTEM_CONFDIR + "/DEBUG").exists()) {
 | 
						|
            log.setLevel(Level.ALL);
 | 
						|
        }
 | 
						|
        if (new File(USER_CONFDIR + "/SQL_DEBUG").exists()
 | 
						|
                || new File(SYSTEM_CONFDIR + "/SQL_DEBUG").exists()) {
 | 
						|
            DriverManager.setLogWriter(new PrintWriter(System.err));
 | 
						|
        }
 | 
						|
        boolean shouldUpdateClasspath = false;
 | 
						|
        ArrayList<URL> urls = new ArrayList<URL>();
 | 
						|
        shouldUpdateClasspath |= findJars(new File(USER_CONFDIR), urls);
 | 
						|
        shouldUpdateClasspath |= findJars(new File(SYSTEM_CONFDIR), urls);
 | 
						|
        if (shouldUpdateClasspath) {
 | 
						|
            ClassLoader parentLoader = Thread.currentThread().getContextClassLoader();
 | 
						|
            ClassLoader loader = new URLClassLoader(urls.toArray(new URL[0]), parentLoader);
 | 
						|
            Thread.currentThread().setContextClassLoader(loader);
 | 
						|
            for (String driverName : SUPPORTED_DRIVERS) {
 | 
						|
                try {
 | 
						|
                    @SuppressWarnings("unchecked")
 | 
						|
                    Class<Driver> driverClass = (Class<Driver>)loader.loadClass(driverName);
 | 
						|
                    DriverManager.registerDriver(new DelegateDriver(driverClass.newInstance()));
 | 
						|
                } catch (Exception e) {
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        try {
 | 
						|
            new sqlcsv().run(args);
 | 
						|
            System.exit(0);
 | 
						|
        } catch (Throwable t) {
 | 
						|
            if (t instanceof InvocationTargetException) t = t.getCause();
 | 
						|
            if (t instanceof Exit) ((Exit)t).exit();
 | 
						|
            die(null, t);
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 |