/***************************************************************************** * Copyright (C) 2008 EnterpriseDB Corporation. * Copyright (C) 2011 Stado Global Development Group. * * This file is part of Stado. * * Stado is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Stado is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Stado. If not, see <http://www.gnu.org/licenses/>. * * You can find Stado at http://www.stado.us * ****************************************************************************/ package org.postgresql.driver.copy; import java.io.IOException; import java.io.InputStream; import java.sql.SQLException; import org.postgresql.driver.PGConnection; import org.postgresql.driver.util.GT; import org.postgresql.driver.util.PSQLException; import org.postgresql.driver.util.PSQLState; /** * InputStream for reading from a PostgreSQL COPY TO STDOUT operation */ public class PGCopyInputStream extends InputStream implements CopyOut { private CopyOut op; private byte[] buf; private int at, len; /** * Uses given connection for specified COPY TO STDOUT operation * @param connection database connection to use for copying (protocol version 3 required) * @param sql COPY TO STDOUT statement * @throws SQLException if initializing the operation fails */ public PGCopyInputStream(PGConnection connection, String sql) throws SQLException { this(connection.getCopyAPI().copyOut(sql)); } /** * Use given CopyOut operation for reading * @param op COPY TO STDOUT operation * @throws SQLException if initializing the operation fails */ public PGCopyInputStream(CopyOut op) { this.op = op; } private boolean gotBuf() throws IOException { if(at >= len) { try { buf = op.readFromCopy(); } catch(SQLException sqle) { throw new IOException(GT.tr("Copying from database failed: {0}", sqle)); } if(buf == null) { at = -1; return false; } else { at = 0; len = buf.length; return true; } } return buf != null; } private void checkClosed() throws IOException { if (op == null) { throw new IOException(GT.tr("This copy stream is closed.")); } } public int available() throws IOException { checkClosed(); return ( buf != null ? len - at : 0 ); } public int read() throws IOException { checkClosed(); return gotBuf() ? buf[at++] : -1; } public int read(byte[] buf) throws IOException { return read(buf, 0, buf.length); } public int read(byte[] buf, int off, int siz) throws IOException { checkClosed(); int got = 0; while( got < siz && gotBuf() ) { buf[off+got++] = this.buf[at++]; } return got; } public byte[] readFromCopy() throws SQLException { byte[] result = buf; try { if(gotBuf()) { if(at>0 || len < buf.length) { byte[] ba = new byte[len-at]; for(int i=at; i<len; i++) ba[i-at] = buf[i]; result = ba; } at = len; // either partly or fully returned, buffer is exhausted } } catch(IOException ioe) { throw new PSQLException(GT.tr("Read from copy failed."), PSQLState.CONNECTION_FAILURE); } return result; } public void close() throws IOException { // Don't complain about a double close. if (op == null) return; try { op.cancelCopy(); } catch(SQLException se) { IOException ioe = new IOException("Failed to close copy reader."); ioe.initCause(se); throw ioe; } op = null; } public void cancelCopy() throws SQLException { op.cancelCopy(); } public void cancelCopyFinish() throws IOException { op.cancelCopyFinish(); } public int getFormat() { return op.getFormat(); } public int getFieldFormat(int field) { return op.getFieldFormat(field); } public int getFieldCount() { return op.getFieldCount(); } public boolean isActive() { return op.isActive(); } public long getHandledRowCount() { return op.getHandledRowCount(); } }