Пример #1
0
// 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
}
Пример #2
0
// 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
}
Пример #3
0
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
}
Пример #4
0
// 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
}
Пример #5
0
// 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
}
Пример #6
0
// 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
}
Пример #7
0
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
}
Пример #8
0
// 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
}