Example #1
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
	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
}
Example #2
0
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
}
Example #3
0
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
}
Example #4
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
}