class PG::Connection
def copy_data( sql, coder=nil )
def copy_data( sql, coder=nil ) raise PG::NotInBlockingMode.new("copy_data can not be used in nonblocking mode", connection: self) if nonblocking? res = exec( sql ) case res.result_status when PGRES_COPY_IN begin if coder && res.binary_tuples == 1 # Binary file header (11 byte signature, 32 bit flags and 32 bit extension length) put_copy_data(BinarySignature + ("\x00" * 8)) end if coder old_coder = self.encoder_for_put_copy_data self.encoder_for_put_copy_data = coder end yield res rescue Exception => err errmsg = "%s while copy data: %s" % [ err.class.name, err.message ] begin put_copy_end( errmsg ) rescue PG::Error # Ignore error in cleanup to avoid losing original exception end discard_results raise err else begin self.encoder_for_put_copy_data = old_coder if coder if coder && res.binary_tuples == 1 put_copy_data("\xFF\xFF") # Binary file trailer 16 bit "-1" end put_copy_end rescue PG::Error => err raise PG::LostCopyState.new("#{err} (probably by executing another SQL query while running a COPY command)", connection: self) end get_last_result ensure self.encoder_for_put_copy_data = old_coder if coder end when PGRES_COPY_OUT begin if coder old_coder = self.decoder_for_get_copy_data self.decoder_for_get_copy_data = coder end yield res rescue Exception cancel discard_results raise else if coder && res.binary_tuples == 1 # There are two end markers in binary mode: file trailer and the final nil. # The file trailer is expected to be processed by BinaryDecoder::CopyRow and already returns nil, so that the remaining NULL from PQgetCopyData is retrieved here: if get_copy_data discard_results raise PG::NotAllCopyDataRetrieved.new("Not all binary COPY data retrieved", connection: self) end end res = get_last_result if !res discard_results raise PG::LostCopyState.new("Lost COPY state (probably by executing another SQL query while running a COPY command)", connection: self) elsif res.result_status != PGRES_COMMAND_OK discard_results raise PG::NotAllCopyDataRetrieved.new("Not all COPY data retrieved", connection: self) end res ensure self.decoder_for_get_copy_data = old_coder if coder end else raise ArgumentError, "SQL command is no COPY statement: #{sql}" end end