package org.xbib.jdbc.csv; import org.xbib.jdbc.io.CryptoFilter; import org.xbib.jdbc.io.DataReader; import org.xbib.jdbc.io.EncryptedFileInputStream; import org.xbib.jdbc.io.FileSetInputStream; import org.xbib.jdbc.io.ListDataReader; import org.xbib.jdbc.io.TableReader; import org.xbib.jdbc.dbf.DbfReader; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.LineNumberReader; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.sql.SQLWarning; import java.sql.Statement; import java.util.ArrayList; import java.util.List; /** * This class implements the java.sql.Statement JDBC interface for the * CsvJdbc driver. */ public class CsvStatement implements Statement { /* * Key for column name in database rows for accessing CsvStatement. */ public static final String STATEMENT_COLUMN_NAME = "@STATEMENT"; private CsvConnection connection; protected ResultSet lastResultSet = null; protected List<SqlParser> multipleParsers = null; private int maxRows = 0; private int fetchSize = 1; private int fetchDirection = ResultSet.FETCH_FORWARD; private boolean closed; protected int resultSetType = ResultSet.TYPE_SCROLL_INSENSITIVE; /** * Creates new Statement for use in executing SQL statements. * * @param connection database connection to create statement for. * @param resultSetType either ResultSet.TYPE_SCROLL_INSENSITIVE or * ResultSet.TYPE_SCROLL_SENSITIVE. */ protected CsvStatement(CsvConnection connection, int resultSetType) { CsvDriver.writeLog("CsvStatement() - connection=" + connection); CsvDriver.writeLog("CsvStatement() - Asked for " + (resultSetType == ResultSet.TYPE_SCROLL_SENSITIVE ? "Scrollable" : "Not Scrollable")); this.connection = connection; this.resultSetType = resultSetType; } protected void checkOpen() throws SQLException { if (closed) { throw new SQLException(CsvResources.getString("statementClosed")); } } @Override public void setMaxFieldSize(int p0) throws SQLException { throw new SQLFeatureNotSupportedException(CsvResources.getString("methodNotSupported") + ": setMaxFieldSize(int)"); } @Override public void setMaxRows(int max) throws SQLException { checkOpen(); maxRows = max; } @Override public void setEscapeProcessing(boolean enable) throws SQLException { throw new SQLFeatureNotSupportedException(CsvResources.getString("methodNotSupported") + ": setEscapeProcessing(boolean)"); } @Override public void setQueryTimeout(int seconds) throws SQLException { throw new SQLFeatureNotSupportedException(CsvResources.getString("methodNotSupported") + ": setQueryTimeout(int)"); } @Override public void setCursorName(String name) throws SQLException { throw new SQLFeatureNotSupportedException(CsvResources.getString("methodNotSupported") + ": setCursorName(String)"); } @Override public void setFetchDirection(int direction) throws SQLException { checkOpen(); if (direction == ResultSet.FETCH_FORWARD || direction == ResultSet.FETCH_REVERSE || direction == ResultSet.FETCH_UNKNOWN) { this.fetchDirection = direction; } else { throw new SQLFeatureNotSupportedException(CsvResources.getString("unsupportedDirection") + ": " + direction); } } @Override public void setFetchSize(int rows) throws SQLException { checkOpen(); this.fetchSize = rows; } @Override public int getMaxFieldSize() throws SQLException { throw new SQLFeatureNotSupportedException(CsvResources.getString("methodNotSupported") + ": getMaxFieldSize()"); } @Override public int getMaxRows() throws SQLException { checkOpen(); return maxRows; } @Override public int getQueryTimeout() throws SQLException { checkOpen(); return 0; } @Override public SQLWarning getWarnings() throws SQLException { checkOpen(); return null; } @Override public ResultSet getResultSet() throws SQLException { checkOpen(); return lastResultSet; } @Override public int getUpdateCount() throws SQLException { checkOpen(); /* * Driver is read-only, so no updates are possible. */ return -1; } @Override public boolean getMoreResults() throws SQLException { checkOpen(); try { /* * Close any ResultSet that is currently open. */ if (lastResultSet != null) { lastResultSet.close(); } } finally { lastResultSet = null; } boolean retval; if (multipleParsers != null && multipleParsers.size() > 0) { /* * There are multiple SELECT statements being executed. Go to the next one. */ lastResultSet = executeParsedQuery(multipleParsers.remove(0)); retval = true; } else { retval = false; } return retval; } @Override public int getFetchDirection() throws SQLException { checkOpen(); return fetchDirection; } @Override public int getFetchSize() throws SQLException { checkOpen(); return fetchSize; } @Override public int getResultSetConcurrency() throws SQLException { checkOpen(); return ResultSet.CONCUR_READ_ONLY; } @Override public int getResultSetType() throws SQLException { checkOpen(); return this.resultSetType; } @Override public Connection getConnection() throws SQLException { checkOpen(); return connection; } @Override public ResultSet executeQuery(String sql) throws SQLException { checkOpen(); CsvDriver.writeLog("CsvStatement:executeQuery() - sql= " + sql); /* * Close any previous ResultSet, as required by JDBC. */ try { if (lastResultSet != null) { lastResultSet.close(); } } finally { lastResultSet = null; multipleParsers = null; } SqlParser parser = new SqlParser(); try { parser.parse(sql); } catch (Exception e) { throw new SQLException(CsvResources.getString("syntaxError") + ": " + e.getMessage()); } return executeParsedQuery(parser); } protected ResultSet executeParsedQuery(SqlParser parser) throws SQLException { String path = connection.getPath(); TableReader tableReader = connection.getTableReader(); if (path != null) { CsvDriver.writeLog("Connection Path: " + path); } else { CsvDriver.writeLog("Connection TableReader: " + tableReader.getClass().getName()); } CsvDriver.writeLog("Parser Table Name: " + parser.getTableName()); CsvDriver.writeLog("Connection Extension: " + connection.getExtension()); DataReader reader = null; String fileName = null; String tableName = parser.getTableName(); if (tableName == null) { /* * Create an empty dataset with one row. */ String[] columnNames = new String[0]; String[] columnTypes = new String[0]; ArrayList<Object[]> rows = new ArrayList<Object[]>(); rows.add(new Object[0]); reader = new ListDataReader(columnNames, columnTypes, rows); } else { if (path != null && (!connection.isIndexedFiles())) { fileName = path + tableName + connection.getExtension(); CsvDriver.writeLog("CSV file name: " + fileName); File checkFile = new File(fileName); if (!checkFile.exists()) { throw new SQLException(CsvResources.getString("fileNotFound") + ": " + fileName); } if (!checkFile.canRead()) { throw new SQLException(CsvResources.getString("fileNotReadable") + ": " + fileName); } } try { if (connection.getExtension().equalsIgnoreCase(".dbf")) { reader = new DbfReader(fileName, parser.getTableAlias(), connection.getCharset()); } else { LineNumberReader input; if (tableReader == null) { InputStream in; CryptoFilter filter = connection.getDecryptingCodec(); if (connection.isIndexedFiles()) { String fileNamePattern = parser.getTableName() + connection.getFileNamePattern() + connection.getExtension(); String[] nameParts = connection.getNameParts(); String dirName = connection.getPath(); in = new FileSetInputStream(dirName, fileNamePattern, nameParts, connection.getSeparator(), connection.isFileTailPrepend(), connection.isSuppressHeaders(), filter, connection.getSkipLeadingDataLines() + connection.getTransposedLines()); } else if (filter == null) { in = new FileInputStream(fileName); } else { filter.reset(); in = new EncryptedFileInputStream(fileName, filter); } if (connection.getCharset() != null) { input = new LineNumberReader(new InputStreamReader(in, connection.getCharset())); } else { input = new LineNumberReader(new InputStreamReader(in)); } } else { /* * Reader for table comes from user-provided class. */ input = new LineNumberReader(tableReader.getReader(this, tableName)); } String headerline = connection.getHeaderline(tableName); CsvRawReader rawReader = new CsvRawReader(input, parser.getTableAlias(), connection.getSeparator(), connection.isSuppressHeaders(), connection.isHeaderFixedWidth(), connection.getQuotechar(), connection.getCommentChar(), headerline, connection.getTrimHeaders(), connection.getTrimValues(), connection.getSkipLeadingLines(), connection.isIgnoreUnparseableLines(), connection.isDefectiveHeaders(), connection.getSkipLeadingDataLines(), connection.getQuoteStyle(), connection.getFixedWidthColumns()); reader = new CsvReader(rawReader, connection.getTransposedLines(), connection.getTransposedFieldsToSkip(), headerline); } } catch (IOException e) { throw new SQLException(CsvResources.getString("fileReadError") + ": " + e); } catch (SQLException e) { throw e; } catch (Exception e) { e.printStackTrace(); throw new SQLException(CsvResources.getString("dataReaderError") + ": " + e); } } CsvResultSet resultSet = null; try { resultSet = new CsvResultSet(this, reader, tableName, parser.getColumns(), parser.isDistinct(), this.resultSetType, parser.getWhereClause(), parser.getGroupByColumns(), parser.getHavingClause(), parser.getOrderByColumns(), parser.getLimit(), parser.getOffset(), connection.getColumnTypes(tableName), connection.getSkipLeadingLines()); lastResultSet = resultSet; } catch (ClassNotFoundException e) { CsvDriver.writeLog("" + e); } return resultSet; } @Override public int executeUpdate(String sql) throws SQLException { throw new SQLFeatureNotSupportedException(CsvResources.getString("methodNotSupported") + ": Statement.executeUpdate(String)"); } @Override public void close() throws SQLException { try { if (lastResultSet != null) { lastResultSet.close(); } } finally { lastResultSet = null; multipleParsers = null; closed = true; connection.removeStatement(this); } } @Override public void cancel() throws SQLException { throw new SQLFeatureNotSupportedException(CsvResources.getString("NotNotSupported") + ": Statement.cancel()"); } @Override public void clearWarnings() throws SQLException { checkOpen(); } @Override public boolean execute(String sql) throws SQLException { CsvDriver.writeLog("CsvStatement:execute() - sql= " + sql); /* * Close any previous ResultSet, as required by JDBC. */ try { if (lastResultSet != null) { lastResultSet.close(); } } finally { lastResultSet = null; multipleParsers = null; } /* * Execute one or more SQL statements. * The method getMoreResults() will be used to step through the results. */ MultipleSqlParser parser = new MultipleSqlParser(); try { List<SqlParser> parsers = parser.parse(sql); lastResultSet = executeParsedQuery(parsers.remove(0)); multipleParsers = parsers; } catch (Exception e) { throw new SQLException(CsvResources.getString("syntaxError") + ": " + e.getMessage()); } return true; } @Override public void addBatch(String sql) throws SQLException { throw new SQLFeatureNotSupportedException(CsvResources.getString("methodNotSupported") + ": Statement.addBatch(String)"); } @Override public void clearBatch() throws SQLException { throw new SQLFeatureNotSupportedException(CsvResources.getString("methodNotSupported") + ": Statement.clearBatch()"); } @Override public int[] executeBatch() throws SQLException { throw new SQLFeatureNotSupportedException(CsvResources.getString("methodNotSupported") + ": Statement.executeBatch()"); } // --------------------------------------------------------------------- // JDBC 3.0 // --------------------------------------------------------------------- @Override public boolean getMoreResults(int current) throws SQLException { throw new SQLFeatureNotSupportedException(CsvResources.getString("methodNotSupported") + ": Statement.getMoreResults(int)"); } @Override public ResultSet getGeneratedKeys() throws SQLException { throw new SQLFeatureNotSupportedException(CsvResources.getString("methodNotSupported") + ": Statement.getGeneratedKeys()"); } @Override public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException { throw new SQLFeatureNotSupportedException(CsvResources.getString("methodNotSupported") + ": Statement.executeUpdate(String,int)"); } @Override public int executeUpdate(String sql, int[] columnIndexes) throws SQLException { throw new SQLFeatureNotSupportedException(CsvResources.getString("methodNotSupported") + ": Statement.executeUpdate(String,int[])"); } @Override public int executeUpdate(String sql, String[] columnNames) throws SQLException { throw new SQLFeatureNotSupportedException(CsvResources.getString("methodNotSupported") + ": Statement.executeUpdate(String,String[])"); } @Override public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { throw new SQLFeatureNotSupportedException(CsvResources.getString("methodNotSupported") + ": Statement.execute(String,int)"); } @Override public boolean execute(String sql, int[] columnIndexes) throws SQLException { throw new SQLFeatureNotSupportedException(CsvResources.getString("methodNotSupported") + ": Statement.execute(String,int[])"); } @Override public boolean execute(String sql, String[] columnNames) throws SQLException { throw new SQLFeatureNotSupportedException(CsvResources.getString("methodNotSupported") + ": Statement.execute(String,String[])"); } @Override public int getResultSetHoldability() throws SQLException { throw new SQLFeatureNotSupportedException(CsvResources.getString("methodNotSupported") + ": Statement.getResultSetHoldability()"); } @Override public boolean isClosed() throws SQLException { return closed; } @Override public boolean isPoolable() throws SQLException { checkOpen(); return false; } @Override public void setPoolable(boolean poolable) throws SQLException { checkOpen(); } @Override public boolean isWrapperFor(Class<?> arg0) throws SQLException { return false; } @Override public <T> T unwrap(Class<T> arg0) throws SQLException { return null; } public boolean isCloseOnCompletion() throws SQLException { checkOpen(); return false; } public void closeOnCompletion() throws SQLException { throw new SQLFeatureNotSupportedException(CsvResources.getString("methodNotSupported") + ": Statement.closeOnCompletion()"); } }