// 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 j := lv.pos * lv.lobVar.typ.size if lv.isFile { // Py_BEGIN_ALLOW_THREADS if err = lv.lobVar.environment.CheckStatus( C.OCILobFileOpen(lv.lobVar.connection.handle, lv.lobVar.environment.errorHandle, (*C.OCILobLocator)(unsafe.Pointer(&lv.lobVar.dataBytes[j])), 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 } length = int64(len(p)) olength := C.ub4(length + 1) if err = lv.lobVar.environment.CheckStatus( C.OCILobRead(lv.lobVar.connection.handle, lv.lobVar.environment.errorHandle, (*C.OCILobLocator)(unsafe.Pointer(&lv.lobVar.dataBytes[j])), &olength, C.ub4(off+1), unsafe.Pointer(&p[0]), C.ub4(len(p)), nil, nil, charsetID, lv.lobVar.typ.charsetForm), "LobRead"); err != nil { // Py_END_ALLOW_THREADS C.OCILobFileClose(lv.lobVar.connection.handle, lv.lobVar.environment.errorHandle, (*C.OCILobLocator)(unsafe.Pointer(&lv.lobVar.dataBytes[j]))) return } if lv.isFile { // Py_BEGIN_ALLOW_THREADS if err = lv.lobVar.environment.CheckStatus( C.OCILobFileClose(lv.lobVar.connection.handle, lv.lobVar.environment.errorHandle, (*C.OCILobLocator)(unsafe.Pointer(&lv.lobVar.dataBytes[j]))), "LobFileClose"); err != nil { return } } return }
func (rc *OCI8Rows) Next(dest []driver.Value) error { rv := C.OCIStmtFetch( (*C.OCIStmt)(rc.s.s), (*C.OCIError)(rc.s.c.err), 1, C.OCI_FETCH_NEXT, C.OCI_DEFAULT) if rv == C.OCI_NO_DATA { return io.EOF } else if rv != C.OCI_SUCCESS { return ociGetError(rc.s.c.err) } for i := range dest { // TODO: switch rc.cols[i].ind if rc.cols[i].ind == -1 { // Null dest[i] = nil continue } else if rc.cols[i].ind != 0 { return errors.New(fmt.Sprintf("Unknown column indicator: %d, col %s", rc.cols[i].ind, rc.cols[i].name)) } switch rc.cols[i].kind { case C.SQLT_DAT: // for test, date are return as timestamp buf := (*[1 << 30]byte)(unsafe.Pointer(rc.cols[i].pbuf))[0:rc.cols[i].rlen] // 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) dest[i] = time.Date( (int(buf[0])-100)*100+(int(buf[1])-100), time.Month(int(buf[2])), int(buf[3]), int(buf[4])-1, int(buf[5])-1, int(buf[6])-1, 0, rc.s.c.location) case C.SQLT_BLOB, C.SQLT_CLOB: ptmp := unsafe.Pointer(uintptr(rc.cols[i].pbuf) + unsafe.Sizeof(unsafe.Pointer(nil))) bamt := (*C.ub4)(ptmp) *bamt = 0 ptmp = unsafe.Pointer(uintptr(rc.cols[i].pbuf) + unsafe.Sizeof(C.ub4(0)) + unsafe.Sizeof(unsafe.Pointer(nil))) b := (*[1 << 30]byte)(ptmp)[0:blobBufSize] var buf []byte again: rv = C.OCILobRead( (*C.OCISvcCtx)(rc.s.c.svc), (*C.OCIError)(rc.s.c.err), *(**C.OCILobLocator)(rc.cols[i].pbuf), bamt, 1, ptmp, C.ub4(blobBufSize), nil, nil, 0, C.SQLCS_IMPLICIT) if rv == C.OCI_NEED_DATA { buf = append(buf, b[:int(*bamt)]...) goto again } if rv != C.OCI_SUCCESS { return ociGetError(rc.s.c.err) } if rc.cols[i].kind == C.SQLT_BLOB { dest[i] = append(buf, b[:int(*bamt)]...) } else { dest[i] = string(append(buf, b[:int(*bamt)]...)) } case C.SQLT_CHR, C.SQLT_AFC, C.SQLT_AVC: buf := (*[1 << 30]byte)(unsafe.Pointer(rc.cols[i].pbuf))[0:rc.cols[i].rlen] switch { case rc.cols[i].ind == 0: // Normal dest[i] = string(buf) case rc.cols[i].ind == -2 || // Field longer than type (truncated) rc.cols[i].ind > 0: // Field longer than type (truncated). Value is original length. dest[i] = string(buf) default: return errors.New(fmt.Sprintf("Unknown column indicator: %d", rc.cols[i].ind)) } case C.SQLT_BIN: // RAW buf := (*[1 << 30]byte)(unsafe.Pointer(rc.cols[i].pbuf))[0:rc.cols[i].rlen] dest[i] = buf case C.SQLT_NUM: // NUMBER buf := (*[21]byte)(unsafe.Pointer(rc.cols[i].pbuf)) dest[i] = buf case C.SQLT_VNU: // VARNUM buf := (*[22]byte)(unsafe.Pointer(rc.cols[i].pbuf)) dest[i] = buf case C.SQLT_INT: // INT buf := (*[1 << 30]byte)(unsafe.Pointer(rc.cols[i].pbuf))[0:rc.cols[i].rlen] dest[i] = buf case C.SQLT_LNG: // LONG buf := (*[1 << 30]byte)(unsafe.Pointer(rc.cols[i].pbuf))[0:rc.cols[i].rlen] dest[i] = buf case C.SQLT_IBDOUBLE, C.SQLT_IBFLOAT: colsize := rc.cols[i].size buf := (*[1 << 30]byte)(unsafe.Pointer(rc.cols[i].pbuf))[0:colsize] if colsize == 4 { v := uint32(buf[3]) v |= uint32(buf[2]) << 8 v |= uint32(buf[1]) << 16 v |= uint32(buf[0]) << 24 // Don't know why bits are inverted that way, but it works if buf[0]&0x80 == 0 { v ^= 0xffffffff } else { v &= 0x7fffffff } dest[i] = math.Float32frombits(v) } else if colsize == 8 { v := uint64(buf[7]) v |= uint64(buf[6]) << 8 v |= uint64(buf[5]) << 16 v |= uint64(buf[4]) << 24 v |= uint64(buf[3]) << 32 v |= uint64(buf[2]) << 40 v |= uint64(buf[1]) << 48 v |= uint64(buf[0]) << 56 // Don't know why bits are inverted that way, but it works if buf[0]&0x80 == 0 { v ^= 0xffffffffffffffff } else { v &= 0x7fffffffffffffff } dest[i] = math.Float64frombits(v) } else { return errors.New(fmt.Sprintf("Unhandled binary float size: %d", colsize)) } case C.SQLT_TIMESTAMP: if rv := C.WrapOCIDateTimeGetDateTime( (*C.OCIEnv)(rc.s.c.env), (*C.OCIError)(rc.s.c.err), *(**C.OCIDateTime)(rc.cols[i].pbuf), ); rv.rv != C.OCI_SUCCESS { return ociGetError(rc.s.c.err) } else { dest[i] = time.Date( int(rv.y), time.Month(rv.m), int(rv.d), int(rv.hh), int(rv.mm), int(rv.ss), int(rv.ff), rc.s.c.location) } case C.SQLT_TIMESTAMP_TZ, C.SQLT_TIMESTAMP_LTZ: tptr := *(**C.OCIDateTime)(rc.cols[i].pbuf) rv := C.WrapOCIDateTimeGetDateTime( (*C.OCIEnv)(rc.s.c.env), (*C.OCIError)(rc.s.c.err), tptr) if rv.rv != C.OCI_SUCCESS { return ociGetError(rc.s.c.err) } rvz := C.WrapOCIDateTimeGetTimeZoneNameOffset( (*C.OCIEnv)(rc.s.c.env), (*C.OCIError)(rc.s.c.err), tptr) if rvz.rv != C.OCI_SUCCESS { return ociGetError(rc.s.c.err) } nnn := C.GoStringN((*C.char)((unsafe.Pointer)(&rvz.zone[0])), C.int(rvz.zlen)) loc, err := time.LoadLocation(nnn) if err != nil { // TODO: reuse locations loc = time.FixedZone(nnn, int(rvz.h)*60*60+int(rvz.m)*60) } dest[i] = time.Date( int(rv.y), time.Month(rv.m), int(rv.d), int(rv.hh), int(rv.mm), int(rv.ss), int(rv.ff), loc) case C.SQLT_INTERVAL_DS: iptr := *(**C.OCIInterval)(rc.cols[i].pbuf) rv := C.WrapOCIIntervalGetDaySecond( (*C.OCIEnv)(rc.s.c.env), (*C.OCIError)(rc.s.c.err), iptr) if rv.rv != C.OCI_SUCCESS { return ociGetError(rc.s.c.err) } dest[i] = int64(time.Duration(rv.d)*time.Hour*24 + time.Duration(rv.hh)*time.Hour + time.Duration(rv.mm)*time.Minute + time.Duration(rv.ss)*time.Second + time.Duration(rv.ff)) case C.SQLT_INTERVAL_YM: iptr := *(**C.OCIInterval)(rc.cols[i].pbuf) rv := C.WrapOCIIntervalGetYearMonth( (*C.OCIEnv)(rc.s.c.env), (*C.OCIError)(rc.s.c.err), iptr) if rv.rv != C.OCI_SUCCESS { return ociGetError(rc.s.c.err) } dest[i] = int64(rv.y)*12 + int64(rv.m) default: return errors.New(fmt.Sprintf("Unhandled column type: %d", rc.cols[i].kind)) } } return nil }
func (rc *OCI8Rows) Next(dest []driver.Value) error { rv := C.OCIStmtFetch( (*C.OCIStmt)(rc.s.s), (*C.OCIError)(rc.s.c.err), 1, C.OCI_FETCH_NEXT, C.OCI_DEFAULT) if rv == C.OCI_ERROR { err := ociGetError(rc.s.c.err) if err.Error()[:9] != "ORA-01405" { return err } } if rv == C.OCI_NO_DATA { return io.EOF } var err error for i := range dest { if rc.cols[i].ind == -1 { //Null dest[i] = nil continue } switch rc.cols[i].kind { case C.SQLT_DAT: buf := (*[1 << 30]byte)(unsafe.Pointer(rc.cols[i].pbuf))[0:rc.cols[i].rlen] //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) datestr := fmt.Sprintf(dateStrFmt, ((int(buf[0])-100)*100)+(int(buf[1])-100), int(buf[2]), int(buf[3]), int(buf[4])-1, int(buf[5])-1, int(buf[6])-1) dest[i], err = time.ParseInLocation(dateFmt, datestr, rc.s.c.location) if err != nil { return fmt.Errorf("Unknown date format:", err) } case C.SQLT_BLOB, C.SQLT_CLOB: var bamt C.ub4 b := make([]byte, rc.cols[i].size) rv = C.OCILobRead( (*C.OCISvcCtx)(rc.s.c.svc), (*C.OCIError)(rc.s.c.err), (*C.OCILobLocator)(rc.cols[i].pbuf), &bamt, 1, unsafe.Pointer(&b[0]), C.ub4(rc.cols[i].size), nil, nil, 0, C.SQLCS_IMPLICIT) if rv == C.OCI_ERROR { return ociGetError(rc.s.c.err) } dest[i] = b case C.SQLT_CHR, C.SQLT_AFC, C.SQLT_AVC: buf := (*[1 << 30]byte)(unsafe.Pointer(rc.cols[i].pbuf))[0:rc.cols[i].rlen] switch { case rc.cols[i].ind == 0: //Normal dest[i] = string(buf) case rc.cols[i].ind == -2 || //Field longer than type (truncated) rc.cols[i].ind > 0: //Field longer than type (truncated). Value is original length. dest[i] = string(buf) default: return errors.New(fmt.Sprintf("Unknown column indicator: %d", rc.cols[i].ind)) } default: return errors.New(fmt.Sprintf("Unhandled column type: %d", rc.cols[i].kind)) } } 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 }