// WriteAt writes data in p into the LOB, starting at off. func (lrw *lobReadWriter) WriteAt(p []byte, off int64) (n int, err error) { //Log.Infof("LobWrite2 off=%d len=%d", off, n) byte_amtp := C.oraub8(len(p)) // Write to Oracle if C.OCILobWrite2( 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, starting position is 1 unsafe.Pointer(&p[0]), //void *bufp, C.oraub8(len(p)), C.OCI_ONE_PIECE, //ub1 piece, nil, //void *ctxp, nil, //OCICallbackLobWrite2 (cbfp) C.ub2(0), //ub2 csid, C.SQLCS_IMPLICIT, //ub1 csfrm ); //fmt.Printf("r %v, current %v, buffer %v\n", r, current, buffer) //fmt.Printf("C.OCI_NEED_DATA %v, C.OCI_SUCCESS %v\n", C.OCI_NEED_DATA, C.OCI_SUCCESS) ) == C.OCI_ERROR { return 0, lrw.ses.srv.env.ociError() } if C.oraub8(off)+byte_amtp > lrw.size { lrw.size = C.oraub8(off) + byte_amtp } return int(byte_amtp), nil }
// 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 }
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 }
// 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 }
// Truncate the lob to the given length. func (lrw *lobReadWriter) Truncate(length int64) error { if C.OCILobTrim2( lrw.ses.ocisvcctx, //OCISvcCtx *svchp, lrw.ses.srv.env.ocierr, //OCIError *errhp, lrw.ociLobLocator, //OCILobLocator *locp, C.oraub8(length), //oraub8 *newlen) ) == C.OCI_ERROR { return lrw.ses.srv.env.ociError() } return 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 writeLob(ociLobLocator *C.OCILobLocator, stmt *Stmt, r io.Reader, lobBufferSize int) error { var actBuf, nextBuf []byte if lobChunkSize >= lobBufferSize { arr := lobChunkPool.Get().([lobChunkSize]byte) defer lobChunkPool.Put(arr) actBuf = arr[:lobBufferSize] arr = lobChunkPool.Get().([lobChunkSize]byte) defer lobChunkPool.Put(arr) nextBuf = arr[:lobBufferSize] } else { actBuf = make([]byte, lobBufferSize) nextBuf = make([]byte, lobBufferSize) } // write bytes to lob locator - at once, as we already have all bytes in memory var n int var byte_amtp, off C.oraub8 var actPiece, nextPiece C.ub1 = C.OCI_FIRST_PIECE, C.OCI_NEXT_PIECE // OCILobWrite2 doesn't support writing zero bytes // nor is writing 1 byte and erasing the one byte supported // therefore, throw an error var err error if n, err = io.ReadFull(r, actBuf); err != nil { switch err { case io.EOF: // no bytes read return errNew("writing a zero-length BLOB is unsupported") case io.ErrUnexpectedEOF: actPiece = C.OCI_ONE_PIECE default: return err } actBuf = actBuf[:n] } for { n = len(actBuf) if n == lobBufferSize { var n2 int if n2, err = io.ReadFull(r, nextBuf[:]); err != nil { switch err { case io.EOF: // no bytes read, lobSize == len(buffer[0]) if actPiece == C.OCI_FIRST_PIECE { actPiece = C.OCI_ONE_PIECE } else { actPiece = C.OCI_LAST_PIECE } case io.ErrUnexpectedEOF: nextPiece = C.OCI_LAST_PIECE default: return err } nextBuf = nextBuf[:n2] } } //Log.Infof("LobWrite2 off=%d len=%d piece=%d", off, n, actPiece) byte_amtp = 0 if actPiece == C.OCI_ONE_PIECE { byte_amtp = C.oraub8(n) } // Write to Oracle if C.OCILobWrite2( stmt.ses.srv.ocisvcctx, //OCISvcCtx *svchp, stmt.ses.srv.env.ocierr, //OCIError *errhp, ociLobLocator, //OCILobLocator *locp, &byte_amtp, //oraub8 *byte_amtp, nil, //oraub8 *char_amtp, off+1, //oraub8 offset, starting position is 1 unsafe.Pointer(&actBuf[0]), //void *bufp, C.oraub8(n), actPiece, //ub1 piece, nil, //void *ctxp, nil, //OCICallbackLobWrite2 (cbfp) C.ub2(0), //ub2 csid, C.SQLCS_IMPLICIT, //ub1 csfrm ); //fmt.Printf("r %v, current %v, buffer %v\n", r, current, buffer) //fmt.Printf("C.OCI_NEED_DATA %v, C.OCI_SUCCESS %v\n", C.OCI_NEED_DATA, C.OCI_SUCCESS) ) == C.OCI_ERROR { return stmt.ses.srv.env.ociError() } off += byte_amtp if actPiece == C.OCI_LAST_PIECE || actPiece == C.OCI_ONE_PIECE { break } actPiece, actBuf = nextPiece, nextBuf } return 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 }