// ReadAt reads into p, starting from off. func (lrw *lobReadWriter) ReadAt(p []byte, off int64) (n int, err error) { byte_amtp := C.oraub8(len(p)) //Log.Infof("LobRead2 off=%d amt=%d", off, len(p)) r := C.OCILobRead2( lrw.ses.ocisvcctx, //OCISvcCtx *svchp, lrw.ses.srv.env.ocierr, //OCIError *errhp, lrw.ociLobLocator, //OCILobLocator *locp, &byte_amtp, //oraub8 *byte_amtp, nil, //oraub8 *char_amtp, C.oraub8(off)+1, //oraub8 offset, offset is 1-based unsafe.Pointer(&p[0]), //void *bufp, C.oraub8(len(p)), //oraub8 bufl, C.OCI_ONE_PIECE, //ub1 piece, nil, //void *ctxp, nil, //OCICallbackLobRead2 (cbfp) C.ub2(0), //ub2 csid, lrw.charsetForm, //ub1 csfrm ); ) //Log.Infof("LobRead2 returned %d amt=%d", r, byte_amtp) switch r { case C.OCI_ERROR: return 0, lrw.ses.srv.env.ociError() case C.OCI_NO_DATA: return int(byte_amtp), io.EOF case C.OCI_INVALID_HANDLE: return 0, fmt.Errorf("Invalid handle %v", lrw.ociLobLocator) } return int(byte_amtp), nil }
// WriteTo writes all data from the LOB into the given Writer. func (lr *lobReader) WriteTo(w io.Writer) (n int64, err error) { defer func() { if closeErr := lr.Close(); closeErr != nil && err == nil { err = closeErr } }() var byte_amtp C.oraub8 // zero arr := lobChunkPool.Get().([lobChunkSize]byte) defer lobChunkPool.Put(arr) buf := arr[:] var k int for { //Log.Infof("WriteTo LobRead2 off=%d amt=%d", lr.off, len(buf)) r := C.OCILobRead2( lr.ses.ocisvcctx, //OCISvcCtx *svchp, lr.ses.srv.env.ocierr, //OCIError *errhp, lr.ociLobLocator, //OCILobLocator *locp, &byte_amtp, //oraub8 *byte_amtp, nil, //oraub8 *char_amtp, lr.off+1, //oraub8 offset, offset is 1-based unsafe.Pointer(&buf[0]), //void *bufp, C.oraub8(len(buf)), //oraub8 bufl, lr.piece, //ub1 piece, nil, //void *ctxp, nil, //OCICallbackLobRead2 (cbfp) C.ub2(0), //ub2 csid, lr.charsetForm, //ub1 csfrm ); ) //Log.Infof("WriteTo LobRead2 returned %d amt=%d piece=%d", r, byte_amtp, lr.piece) switch r { case C.OCI_SUCCESS: case C.OCI_NO_DATA: break default: return 0, lr.ses.srv.env.ociError() } // byte_amtp represents the amount copied into buffer by oci lr.off += byte_amtp if byte_amtp != 0 { if k, err = w.Write(buf[:int(byte_amtp)]); err != nil { return n, err } n += int64(k) if lr.off == lr.Length { break } } if lr.piece == C.OCI_FIRST_PIECE { lr.piece = C.OCI_NEXT_PIECE } } return n, nil }
// Read into p, the next chunk. func (lr *lobReader) Read(p []byte) (n int, err error) { if lr.ociLobLocator == nil { return 0, io.EOF } defer func() { if err != nil { lr.Close() } }() var byte_amtp C.oraub8 // zero //Log.Infof("LobRead2 piece=%d off=%d amt=%d", lr.piece, lr.off, len(p)) r := C.OCILobRead2( lr.ses.ocisvcctx, //OCISvcCtx *svchp, lr.ses.srv.env.ocierr, //OCIError *errhp, lr.ociLobLocator, //OCILobLocator *locp, &byte_amtp, //oraub8 *byte_amtp, nil, //oraub8 *char_amtp, lr.off+1, //oraub8 offset, offset is 1-based unsafe.Pointer(&p[0]), //void *bufp, C.oraub8(len(p)), //oraub8 bufl, lr.piece, //ub1 piece, nil, //void *ctxp, nil, //OCICallbackLobRead2 (cbfp) C.ub2(0), //ub2 csid, lr.charsetForm, //ub1 csfrm ); ) //Log.Infof("LobRead2 returned %d amt=%d", r, byte_amtp) switch r { case C.OCI_ERROR: lr.interrupted = true return 0, lr.ses.srv.env.ociError() case C.OCI_NO_DATA: return int(byte_amtp), io.EOF case C.OCI_INVALID_HANDLE: return 0, fmt.Errorf("Invalid handle %v", lr.ociLobLocator) } // byte_amtp represents the amount copied into buffer by oci if byte_amtp != 0 { lr.off += byte_amtp if lr.off == lr.Length { return int(byte_amtp), io.EOF } if lr.piece == C.OCI_FIRST_PIECE { lr.piece = C.OCI_NEXT_PIECE } } return int(byte_amtp), nil }
func (def *defLob) Bytes() (value []byte, err error) { // Open the lob to obtain length; round-trip to database //Log.Infof("Bytes OCILobOpen %p", def.ociLobLocator) lobLength, err := lobOpen(def.rset.stmt.ses, def.ociLobLocator, C.OCI_LOB_READONLY) if err != nil { def.ociLobLocator = nil return nil, err } defer func() { //Log.Infof("Bytes OCILobClose %p", def.ociLobLocator) if closeErr := lobClose(def.rset.stmt.ses, def.ociLobLocator); closeErr != nil && err == nil { err = closeErr } }() if lobLength == 0 { return nil, nil } // Allocate []byte the length of the lob value = make([]byte, int(lobLength)) for off, byte_amtp := 0, lobLength; byte_amtp > 0; byte_amtp = lobLength - C.oraub8(off) { //Log.Infof("LobRead2 off=%d amt=%d", off, byte_amtp) r := C.OCILobRead2( def.rset.stmt.ses.ocisvcctx, //OCISvcCtx *svchp, def.rset.stmt.ses.srv.env.ocierr, //OCIError *errhp, def.ociLobLocator, //OCILobLocator *locp, &byte_amtp, //oraub8 *byte_amtp, nil, //oraub8 *char_amtp, C.oraub8(off+1), //oraub8 offset, offset is 1-based unsafe.Pointer(&value[off]), //void *bufp, C.oraub8(lobChunkSize), //oraub8 bufl, C.OCI_ONE_PIECE, //ub1 piece, nil, //void *ctxp, nil, //OCICallbackLobRead2 (cbfp) C.ub2(0), //ub2 csid, def.charsetForm) //ub1 csfrm ); if r == C.OCI_ERROR { return nil, def.rset.stmt.ses.srv.env.ociError() } // byte_amtp represents the amount copied into buffer by oci off += int(byte_amtp) } return value, nil }
// internalRead returns the size of the LOB variable for internal comsumption. func (lv *ExternalLobVar) internalRead(p []byte, off int64) (length int64, err error) { var charsetID C.ub2 if lv.isFile { // Py_BEGIN_ALLOW_THREADS if CTrace { ctrace("OCILobFileOpen(conn=%p, lob=%x, OCI_FILE_READONLY)", lv.lobVar.connection.handle, lv.getHandleBytes()) } if err = lv.lobVar.environment.CheckStatus( C.OCILobFileOpen(lv.lobVar.connection.handle, lv.lobVar.environment.errorHandle, lv.getHandle(), C.OCI_FILE_READONLY), "LobFileOpen"); err != nil { return } } // Py_END_ALLOW_THREADS // Py_BEGIN_ALLOW_THREADS if lv.lobVar.typ == NClobVarType { // charsetID = C.OCI_UTF16ID charsetID = CsIDAl32UTF8 } else { charsetID = 0 } var ( byteLen2 = C.oraub8(len(p)) charLen2 = C.oraub8(0) byteLen = C.ub4(len(p)) status C.sword pos = int(0) ) for { if useLobRead2 { if CTrace { ctrace("OCILobRead2(conn=%p, lob=%x, byteLen=%d, charLen=%d, off=%d, &p=%p "+ "len(p)=%d, piece=%d, csID=%d, csF=%d", lv.lobVar.connection.handle, lv.getHandleBytes(), byteLen2, charLen2, off+1, &p[pos], len(p)-pos, C.OCI_ONE_PIECE, charsetID, lv.lobVar.typ.charsetForm) } status = C.OCILobRead2(lv.lobVar.connection.handle, lv.lobVar.environment.errorHandle, lv.getHandle(), &byteLen2, &charLen2, C.oraub8(off+1), unsafe.Pointer(&p[pos]), C.oraub8(len(p)-pos), C.OCI_ONE_PIECE, nil, nil, charsetID, lv.lobVar.typ.charsetForm) } else { if CTrace { //log.Printf("p=%q len(p)=%d pos=%d byteLen=%d", p, len(p), pos, byteLen) ctrace("OCILobRead(conn=%p, lob=%x, byteLen=%d, off=%d, &p=%p "+ "len(p)=%d, csID=%d, csF=%d", lv.lobVar.connection.handle, lv.getHandleBytes(), byteLen, off+1, &p[pos], len(p)-pos, charsetID, lv.lobVar.typ.charsetForm) } status = C.OCILobRead(lv.lobVar.connection.handle, lv.lobVar.environment.errorHandle, lv.getHandle(), &byteLen, C.ub4(off+1), unsafe.Pointer(&p[pos]), C.ub4(len(p)-pos), nil, nil, charsetID, lv.lobVar.typ.charsetForm) } if !(status == C.OCI_SUCCESS || status == C.OCI_NEED_DATA) { err = lv.lobVar.environment.CheckStatus(status, "LobRead") if CTrace { ctrace("OCILobFileClose(conn=%p, lob=%p)", lv.lobVar.connection.handle, lv.getHandleBytes()) } C.OCILobFileClose(lv.lobVar.connection.handle, lv.lobVar.environment.errorHandle, lv.getHandle()) return } if useLobRead2 { byteLen = C.ub4(byteLen2) } off += int64(byteLen) length += int64(byteLen) if CTrace { if useLobRead2 { ctrace("(byteLen2=%d charLen2=%d) => length=%d off=%d", byteLen2, charLen2, length, off) } else { ctrace("byteLen=%d => length=%d off=%d", byteLen, length, off) } } if status == C.OCI_SUCCESS { break } pos += int(byteLen) if useLobRead2 { byteLen2 = C.oraub8(len(p) - pos) } else { byteLen = C.ub4(len(p) - pos) } } if lv.isFile { // Py_BEGIN_ALLOW_THREADS if CTrace { ctrace("OCILobFileClose(conn=%p, lob=%x)", lv.lobVar.connection.handle, lv.getHandleBytes()) } if err = lv.lobVar.environment.CheckStatus( C.OCILobFileClose(lv.lobVar.connection.handle, lv.lobVar.environment.errorHandle, lv.getHandle()), "LobFileClose"); err != nil { return } } if 0 == length && err == nil { err = io.EOF } if CTrace { ctrace("internalRead returns %d, %s", length, err) } return }