Пример #1
0
// SetFileName sets the directory alias and file name for the BFILE lob.
func (lv *ExternalLobVar) SetFileName(dirAlias, name string) error {
	var err error
	// create a string for retrieving the value
	if err = lv.Verify(); err != nil {
		return errgo.Mask(err)
	}
	nameB := []byte(name)
	dirAliasB := []byte(dirAlias)

	if CTrace {
		ctrace("OCILobSetFilename(conn=%p, lob=%x, dirAlias=%s, dirAliasLen=%d, name=%s, nameLen=%d)",
			lv.lobVar.connection.handle, lv.getHandleBytes(),
			dirAliasB, len(dirAlias), nameB, len(nameB))
	}
	lob := lv.getHandle()
	if err = lv.lobVar.environment.CheckStatus(
		C.OCILobFileSetName(lv.lobVar.environment.handle,
			lv.lobVar.environment.errorHandle,
			&lob,
			(*C.OraText)(&dirAliasB[0]), C.ub2(len(dirAliasB)),
			(*C.OraText)(&nameB[0]), C.ub2(len(nameB))),
		"LobFileSetName"); err != nil {
		return errgo.Mask(err)
	}

	return nil
}
Пример #2
0
func (bnd *bndBfile) bind(value Bfile, position int, stmt *Stmt) error {
	// DirectoryAlias must be specified to avoid error "ORA-24801: illegal parameter value in OCI lob function"
	// Raising a driver error clarifies the user error
	if value.DirectoryAlias == "" {
		return errNew("DirectoryAlias must be specified when binding a non-null Bfile")
	}
	// Filename must be specified to avoid error "ORA-24801: illegal parameter value in OCI lob function"
	// Raising a driver error clarifies the user error
	if value.Filename == "" {
		return errNew("Filename must be specified when binding a non-null Bfile")
	}

	bnd.stmt = stmt
	// Allocate lob locator handle
	r := C.OCIDescriptorAlloc(
		unsafe.Pointer(bnd.stmt.ses.srv.env.ocienv),           //CONST dvoid   *parenth,
		(*unsafe.Pointer)(unsafe.Pointer(&bnd.ociLobLocator)), //dvoid         **descpp,
		C.OCI_DTYPE_FILE,                                      //ub4           type,
		0,                                                     //size_t        xtramem_sz,
		nil)                                                   //dvoid         **usrmempp);
	if r == C.OCI_ERROR {
		return bnd.stmt.ses.srv.env.ociError()
	} else if r == C.OCI_INVALID_HANDLE {
		return errNew("unable to allocate oci lob handle during bind")
	}

	bnd.cDirectoryAlias = C.CString(value.DirectoryAlias)
	bnd.cFilename = C.CString(value.Filename)
	r = C.OCILobFileSetName(
		bnd.stmt.ses.srv.env.ocienv,                       //OCIEnv             *envhp,
		bnd.stmt.ses.srv.env.ocierr,                       //OCIError           *errhp,
		&bnd.ociLobLocator,                                //OCILobLocator      **filepp,
		(*C.OraText)(unsafe.Pointer(bnd.cDirectoryAlias)), //const OraText      *dir_alias,
		C.ub2(len(value.DirectoryAlias)),                  //ub2                d_length,
		(*C.OraText)(unsafe.Pointer(bnd.cFilename)),       //const OraText      *filename,
		C.ub2(len(value.Filename)))                        //ub2                f_length );
	if r == C.OCI_ERROR {
		return bnd.stmt.ses.srv.env.ociError()
	}
	r = C.OCIBINDBYPOS(
		bnd.stmt.ocistmt,                                //OCIStmt      *stmtp,
		(**C.OCIBind)(&bnd.ocibnd),                      //OCIBind      **bindpp,
		bnd.stmt.ses.srv.env.ocierr,                     //OCIError     *errhp,
		C.ub4(position),                                 //ub4          position,
		unsafe.Pointer(&bnd.ociLobLocator),              //void         *valuep,
		C.LENGTH_TYPE(unsafe.Sizeof(bnd.ociLobLocator)), //sb8          value_sz,
		C.SQLT_FILE,   //ub2          dty,
		nil,           //void         *indp,
		nil,           //ub2          *alenp,
		nil,           //ub2          *rcodep,
		0,             //ub4          maxarr_len,
		nil,           //ub4          *curelep,
		C.OCI_DEFAULT) //ub4          mode );
	if r == C.OCI_ERROR {
		return bnd.stmt.ses.srv.env.ociError()
	}
	return nil
}
Пример #3
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
}
Пример #4
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
}
Пример #5
0
// GetCharacterSetName retrieves the IANA character set name for the attribute.
func (env *Environment) GetCharacterSetName(attribute uint32) (string, error) {
	//, overrideValue string
	var (
		charsetID, vsize C.ub4
		status           C.sword
		err              error
	)

	/*
	   // if override value specified, use it
	   if (overrideValue) {
	       *result = PyMem_Malloc(strlen(overrideValue) + 1);
	       if (!*result)
	           return -1;
	       strcpy(*result, overrideValue);
	       return 0;
	   }
	*/

	// get character set id
	status = C.OCIAttrGet(unsafe.Pointer(env.handle), //void *trgthndlp
		C.OCI_HTYPE_ENV,            //ub4 trghndltyp
		unsafe.Pointer(&charsetID), //void *attributep
		&vsize,           //ub4 *sizep
		C.ub4(attribute), //ub4 attrtype
		env.errorHandle)  //OCIError *errhp
	if err = env.CheckStatus(status, "GetCharacterSetName[get charset id]"); err != nil {
		return "", errgo.Mask(err)
	}

	charsetName := make([]byte, C.OCI_NLS_MAXBUFSZ)
	ianaCharsetName := make([]byte, C.OCI_NLS_MAXBUFSZ)

	// get character set name
	if err = env.CheckStatus(C.OCINlsCharSetIdToName(unsafe.Pointer(env.handle),
		(*C.oratext)(&charsetName[0]),
		C.OCI_NLS_MAXBUFSZ, C.ub2(charsetID)),
		"GetCharacterSetName[get Oracle charset name]"); err != nil {
		return "", errgo.Mask(

			// get IANA character set name
			err)
	}

	status = C.OCINlsNameMap(unsafe.Pointer(env.handle),
		(*C.oratext)(&ianaCharsetName[0]),
		C.OCI_NLS_MAXBUFSZ, (*C.oratext)(&charsetName[0]),
		C.OCI_NLS_CS_ORA_TO_IANA)
	if err = env.CheckStatus(status, "GetCharacterSetName[translate NLS charset]"); err != nil {
		return "", errgo.Mask(

			// store results
			// oratext = unsigned char
			err)
	}

	return string(ianaCharsetName), nil
}
Пример #6
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
}
Пример #7
0
// SetFileName sets the directory alias and file name for the BFILE lob.
func (lv *ExternalLobVar) SetFileName(dirAlias, name string) error {
	var err error
	// create a string for retrieving the value
	if err = lv.Verify(); err != nil {
		return err
	}
	nameB := []byte(name)
	dirAliasB := []byte(dirAlias)

	if err = lv.lobVar.environment.CheckStatus(
		C.OCILobFileSetName(lv.lobVar.environment.handle,
			lv.lobVar.environment.errorHandle,
			(**C.OCILobLocator)(unsafe.Pointer(&lv.lobVar.dataBytes[lv.pos*lv.lobVar.size])),
			(*C.OraText)(&dirAliasB[0]), C.ub2(len(dirAliasB)),
			(*C.OraText)(&nameB[0]), C.ub2(len(nameB))),
		"LobFileSetName"); err != nil {
		return err
	}

	return nil
}
Пример #8
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
}
Пример #9
0
func (def *defBfile) value() (value interface{}, err error) {
	var bfileValue Bfile
	bfileValue.IsNull = def.null < C.sb2(0)
	if !bfileValue.IsNull {
		// Get directory alias and filename
		dLength := C.ub2(len(def.directoryAlias))
		fLength := C.ub2(len(def.filename))
		r := C.OCILobFileGetName(
			def.rset.stmt.ses.srv.env.ocienv,                     //OCIEnv                   *envhp,
			def.rset.stmt.ses.srv.env.ocierr,                     //OCIError                 *errhp,
			def.ociLobLocator,                                    //const OCILobLocator      *filep,
			(*C.OraText)(unsafe.Pointer(&def.directoryAlias[0])), //OraText                  *dir_alias,
			&dLength, //ub2                      *d_length,
			(*C.OraText)(unsafe.Pointer(&def.filename[0])), //OraText                  *filename,
			&fLength) //ub2                      *f_length );
		if r == C.OCI_ERROR {
			return value, def.rset.stmt.ses.srv.env.ociError()
		}
		bfileValue.DirectoryAlias = string(def.directoryAlias[:int(dLength)])
		bfileValue.Filename = string(def.filename[:int(fLength)])
	}
	value = bfileValue
	return value, err
}
Пример #10
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
}
Пример #11
0
// Set the value of the variable.
func stringVarSetValue(v *Variable, pos uint, value interface{}) (err error) {
	var (
		text   string
		buf    []byte
		ok     bool
		length int
	)
	if text, ok = value.(string); !ok {
		if buf, ok = value.([]byte); !ok {
			if arr, ok := value.([]string); ok {
				for i := range arr {
					if err = stringVarSetValue(v, pos+uint(i), arr[i]); err != nil {
						return fmt.Errorf("error setting pos=%d + %d. element: %s", pos, i, err)
					}
				}
				return nil
			} else if arr, ok := value.([]byte); ok {
				for i := range arr {
					if err = stringVarSetValue(v, pos+uint(i), arr[i]); err != nil {
						return fmt.Errorf("error setting pos=%d + %d. element: %s", pos, i, err)
					}
				}
				return nil
			}
			// return fmt.Errorf("string or []byte required, got %T", value)
			log.Panicf("string or []byte required, got %T", value)
		} else {
			if v.typ.isCharData {
				text = string(buf)
				length = len(text)
			} else {
				length = len(buf)
			}
		}
	} else {
		if v.typ.isCharData {
			length = len(text)
		} else {
			length = len(buf)
		}
		buf = []byte(text)
	}
	if v.typ.isCharData && length > MaxStringChars {
		return errors.New("string data too large")
	} else if !v.typ.isCharData && length > MaxBinaryBytes {
		return errors.New("binary data too large")
	}

	// ensure that the buffer is large enough
	if length > int(v.bufferSize) {
		if err := v.resize(uint(length)); err != nil {
			return err
		}
	}

	// keep a copy of the string
	v.actualLength[pos] = C.ub2(length)
	if length > 0 {
		copy(v.dataBytes[int(v.bufferSize*pos):], buf)
	}

	return nil
}
Пример #12
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
}
Пример #13
0
// Set the value of the variable.
func stringVarSetValue(v *Variable, pos uint, value interface{}) (err error) {
	if value == nil {
		v.actualLength[pos] = C.ub2(0)
		return nil
	}
	var (
		buf    []byte
		length int
	)

	switch x := value.(type) {
	case string:
		buf = []byte(x)
		length = len(buf)
	case []byte:
		buf = x
		length = len(buf)
	case []string:
		for i := range x {
			if err = stringVarSetValue(v, pos+uint(i), x[i]); err != nil {
				return errgo.Newf("error setting pos=%d + %d. element: %s", pos, i, err)
			}
		}
		return nil
	case [][]byte:
		for i := range x {
			if err = stringVarSetValue(v, pos+uint(i), x[i]); err != nil {
				return errgo.Newf("error setting pos=%d + %d. element: %s", pos, i, err)
			}
		}
		return nil
	case *Variable:
		switch {
		case x == nil:
		case x.actualLength != nil:
			length = int(x.actualLength[pos])
			buf = v.dataBytes[int(v.bufferSize*pos):]
		default:
			length = len(v.dataBytes) / int(v.bufferSize)
			buf = v.dataBytes
		}
	default:
		log.Panicf("string or []byte required, got %T", value)
	}
	if v.typ.isCharData && length > MaxStringChars {
		return errgo.New("string data too large")
	} else if !v.typ.isCharData && length > MaxBinaryBytes {
		return errgo.New("binary data too large")
	}

	// ensure that the buffer is large enough
	if length > int(v.bufferSize) {
		if err := v.resize(uint(length)); err != nil {
			return errgo.Mask(err)
		}
	}

	// keep a copy of the string
	v.actualLength[pos] = C.ub2(length)
	if length > 0 {
		copy(v.dataBytes[int(v.bufferSize*pos):], buf)
	}

	return nil
}
Пример #14
0
func (s *OCI8Stmt) bind(args []driver.Value) (freeBoundParameters func(), err error) {
	if args == nil {
		return func() {}, nil
	}

	var (
		bp              *C.OCIBind
		dty             int
		data            []byte
		cdata           *C.char
		boundParameters []*C.char
	)

	freeBoundParameters = func() {
		for _, p := range boundParameters {
			C.free(unsafe.Pointer(p))
		}
	}

	for i, v := range args {
		data = []byte{}

		switch v.(type) {
		case nil:
			dty = C.SQLT_STR
			data = []byte{0}
		case time.Time:
			dty = C.SQLT_DAT
			now := v.(time.Time).In(s.c.location)
			//TODO Handle BCE dates (http://docs.oracle.com/cd/B12037_01/appdev.101/b10779/oci03typ.htm#438305)
			//TODO Handle timezones (http://docs.oracle.com/cd/B12037_01/appdev.101/b10779/oci03typ.htm#443601)
			data = []byte{
				byte(now.Year()/100 + 100),
				byte(now.Year()%100 + 100),
				byte(now.Month()),
				byte(now.Day()),
				byte(now.Hour() + 1),
				byte(now.Minute() + 1),
				byte(now.Second() + 1),
			}
		default:
			dty = C.SQLT_STR
			data = []byte(fmt.Sprintf("%v", v))
			data = append(data, 0)
		}

		cdata = C.CString(string(data))
		boundParameters = append(boundParameters, cdata)
		rv := C.OCIBindByPos(
			(*C.OCIStmt)(s.s),
			&bp,
			(*C.OCIError)(s.c.err),
			C.ub4(i+1),
			unsafe.Pointer(cdata),
			C.sb4(len(data)),
			C.ub2(dty),
			nil,
			nil,
			nil,
			0,
			nil,
			C.OCI_DEFAULT)

		if rv == C.OCI_ERROR {
			defer freeBoundParameters()
			return nil, ociGetError(s.c.err)
		}
	}
	return freeBoundParameters, nil
}