// ColumnTypeScanType implement RowsColumnTypeScanType. func (rc *OCI8Rows) ColumnTypeScanType(i int) reflect.Type { var p unsafe.Pointer var tp C.ub2 tpr := C.WrapOCIAttrGetUb2(p, C.OCI_DTYPE_PARAM, C.OCI_ATTR_DATA_TYPE, (*C.OCIError)(rc.s.c.err)) if tpr.rv == C.OCI_SUCCESS { tp = tpr.num } switch tp { case C.SQLT_CHR, C.SQLT_AFC, C.SQLT_VCS, C.SQLT_AVC: return reflect.SliceOf(reflect.TypeOf("")) case C.SQLT_BIN: return reflect.SliceOf(reflect.TypeOf(byte(0))) case C.SQLT_NUM: return reflect.TypeOf(int64(0)) case C.SQLT_IBDOUBLE, C.SQLT_IBFLOAT: return reflect.TypeOf(float64(0)) case C.SQLT_CLOB, C.SQLT_BLOB: return reflect.SliceOf(reflect.TypeOf(byte(0))) case C.SQLT_TIMESTAMP, C.SQLT_DAT: return reflect.TypeOf(time.Time{}) case C.SQLT_TIMESTAMP_TZ, C.SQLT_TIMESTAMP_LTZ: return reflect.TypeOf(time.Time{}) case C.SQLT_INTERVAL_DS: return reflect.TypeOf(time.Duration(0)) case C.SQLT_INTERVAL_YM: return reflect.TypeOf(time.Duration(0)) case C.SQLT_RDD: // rowid return reflect.SliceOf(reflect.TypeOf("")) default: return reflect.SliceOf(reflect.TypeOf("")) } return reflect.SliceOf(reflect.TypeOf(byte(0))) }
func (rc *OCI8Rows) ColumnTypeLength(i int) (length int64, ok bool) { var p unsafe.Pointer var lp C.ub2 rp := C.WrapOCIParamGet(rc.s.s, C.OCI_HTYPE_STMT, (*C.OCIError)(rc.s.c.err), C.ub4(i+1)) if rp.rv != C.OCI_SUCCESS { return 0, false } p = rp.ptr lpr := C.WrapOCIAttrGetUb2(p, C.OCI_DTYPE_PARAM, C.OCI_ATTR_DATA_SIZE, (*C.OCIError)(rc.s.c.err)) if lpr.rv != C.OCI_SUCCESS { return 0, false } lp = lpr.num return int64(lp), true }
func (s *OCI8Stmt) Query(args []driver.Value) (rows driver.Rows, err error) { var ( fbp []oci8bind ) if fbp, err = s.bind(args); err != nil { return nil, err } defer freeBoundParameters(fbp) iter := C.ub4(1) if retUb2 := C.WrapOCIAttrGetUb2(s.s, C.OCI_HTYPE_STMT, C.OCI_ATTR_STMT_TYPE, (*C.OCIError)(s.c.err)); retUb2.rv != C.OCI_SUCCESS { return nil, ociGetError(s.c.err) } else if retUb2.num == C.OCI_STMT_SELECT { iter = 0 } // set the row prefetch. Only one extra row per fetch will be returned unless this is set. if prefetch_size := C.ub4(s.c.attrs.Get("prefetch_rows").(int)); prefetch_size > 0 { if rv := C.WrapOCIAttrSetUb4(s.s, C.OCI_HTYPE_STMT, prefetch_size, C.OCI_ATTR_PREFETCH_ROWS, (*C.OCIError)(s.c.err)); rv != C.OCI_SUCCESS { return nil, ociGetError(s.c.err) } } // if non-zero, oci will fetch rows until the memory limit or row prefetch limit is hit. // useful for memory constrained systems if prefetch_memory := C.ub4(s.c.attrs.Get("prefetch_memory").(int64)); prefetch_memory > 0 { if rv := C.WrapOCIAttrSetUb4(s.s, C.OCI_HTYPE_STMT, prefetch_memory, C.OCI_ATTR_PREFETCH_MEMORY, (*C.OCIError)(s.c.err)); rv != C.OCI_SUCCESS { return nil, ociGetError(s.c.err) } } mode := C.ub4(C.OCI_DEFAULT) if !s.c.inTransaction { mode = mode | C.OCI_COMMIT_ON_SUCCESS } if rv := C.OCIStmtExecute( (*C.OCISvcCtx)(s.c.svc), (*C.OCIStmt)(s.s), (*C.OCIError)(s.c.err), iter, 0, nil, nil, mode); rv != C.OCI_SUCCESS { return nil, ociGetError(s.c.err) } var rc int if retUb2 := C.WrapOCIAttrGetUb2(s.s, C.OCI_HTYPE_STMT, C.OCI_ATTR_PARAM_COUNT, (*C.OCIError)(s.c.err)); retUb2.rv != C.OCI_SUCCESS { return nil, ociGetError(s.c.err) } else { rc = int(retUb2.num) } oci8cols := make([]oci8col, rc) for i := 0; i < rc; i++ { var p unsafe.Pointer var tp C.ub2 var lp C.ub2 if rp := C.WrapOCIParamGet(s.s, C.OCI_HTYPE_STMT, (*C.OCIError)(s.c.err), C.ub4(i+1)); rp.rv != C.OCI_SUCCESS { return nil, ociGetError(s.c.err) } else { p = rp.ptr } if tpr := C.WrapOCIAttrGetUb2(p, C.OCI_DTYPE_PARAM, C.OCI_ATTR_DATA_TYPE, (*C.OCIError)(s.c.err)); tpr.rv != C.OCI_SUCCESS { return nil, ociGetError(s.c.err) } else { tp = tpr.num } if nsr := C.WrapOCIAttrGetString(p, C.OCI_DTYPE_PARAM, C.OCI_ATTR_NAME, (*C.OCIError)(s.c.err)); nsr.rv != C.OCI_SUCCESS { return nil, ociGetError(s.c.err) } else { oci8cols[i].name = string((*[1 << 30]byte)(unsafe.Pointer(nsr.ptr))[0:int(nsr.size)]) } if lpr := C.WrapOCIAttrGetUb2(p, C.OCI_DTYPE_PARAM, C.OCI_ATTR_DATA_SIZE, (*C.OCIError)(s.c.err)); lpr.rv != C.OCI_SUCCESS { return nil, ociGetError(s.c.err) } else { lp = lpr.num } /* var ( defp *C.OCIDefine ) */ *s.defp = nil switch tp { case C.SQLT_CHR, C.SQLT_AFC, C.SQLT_VCS, C.SQLT_AVC: // TODO: transfer as clob, read all bytes in loop // lp *= 4 // utf8 enc oci8cols[i].kind = C.SQLT_CHR // tp oci8cols[i].size = int(lp) * 4 // utf8 enc oci8cols[i].pbuf = C.malloc(C.size_t(oci8cols[i].size) + 1) case C.SQLT_BIN: oci8cols[i].kind = C.SQLT_BIN oci8cols[i].size = int(lp) oci8cols[i].pbuf = C.malloc(C.size_t(oci8cols[i].size)) case C.SQLT_NUM: oci8cols[i].kind = C.SQLT_CHR oci8cols[i].size = int(lp * 4) oci8cols[i].pbuf = C.malloc(C.size_t(oci8cols[i].size) + 1) case C.SQLT_IBDOUBLE, C.SQLT_IBFLOAT: oci8cols[i].kind = C.SQLT_IBDOUBLE oci8cols[i].size = int(8) oci8cols[i].pbuf = C.malloc(8) case C.SQLT_CLOB, C.SQLT_BLOB: // allocate +io buffers + ub4 size := int(unsafe.Sizeof(unsafe.Pointer(nil)) + unsafe.Sizeof(C.ub4(0))) if oci8cols[i].size < blobBufSize { size += blobBufSize } else { size += oci8cols[i].size } if ret := C.WrapOCIDescriptorAlloc(s.c.env, C.OCI_DTYPE_LOB, C.size_t(size)); ret.rv != C.OCI_SUCCESS { return nil, ociGetError(s.c.err) } else { oci8cols[i].kind = tp oci8cols[i].size = int(unsafe.Sizeof(unsafe.Pointer(nil))) oci8cols[i].pbuf = ret.extra *(*unsafe.Pointer)(ret.extra) = ret.ptr } // testing // case C.SQLT_DAT: // // oci8cols[i].kind = C.SQLT_DAT // oci8cols[i].size = int(lp) // oci8cols[i].pbuf = C.malloc(C.size_t(lp)) // case C.SQLT_TIMESTAMP, C.SQLT_DAT: if ret := C.WrapOCIDescriptorAlloc(s.c.env, C.OCI_DTYPE_TIMESTAMP, C.size_t(unsafe.Sizeof(unsafe.Pointer(nil)))); ret.rv != C.OCI_SUCCESS { return nil, ociGetError(s.c.err) } else { oci8cols[i].kind = C.SQLT_TIMESTAMP oci8cols[i].size = int(unsafe.Sizeof(unsafe.Pointer(nil))) oci8cols[i].pbuf = ret.extra *(*unsafe.Pointer)(ret.extra) = ret.ptr } case C.SQLT_TIMESTAMP_TZ, C.SQLT_TIMESTAMP_LTZ: if ret := C.WrapOCIDescriptorAlloc(s.c.env, C.OCI_DTYPE_TIMESTAMP_TZ, C.size_t(unsafe.Sizeof(unsafe.Pointer(nil)))); ret.rv != C.OCI_SUCCESS { return nil, ociGetError(s.c.err) } else { oci8cols[i].kind = C.SQLT_TIMESTAMP_TZ oci8cols[i].size = int(unsafe.Sizeof(unsafe.Pointer(nil))) oci8cols[i].pbuf = ret.extra *(*unsafe.Pointer)(ret.extra) = ret.ptr } case C.SQLT_INTERVAL_DS: if ret := C.WrapOCIDescriptorAlloc(s.c.env, C.OCI_DTYPE_INTERVAL_DS, C.size_t(unsafe.Sizeof(unsafe.Pointer(nil)))); ret.rv != C.OCI_SUCCESS { return nil, ociGetError(s.c.err) } else { oci8cols[i].kind = C.SQLT_INTERVAL_DS oci8cols[i].size = int(unsafe.Sizeof(unsafe.Pointer(nil))) oci8cols[i].pbuf = ret.extra *(*unsafe.Pointer)(ret.extra) = ret.ptr } case C.SQLT_INTERVAL_YM: if ret := C.WrapOCIDescriptorAlloc(s.c.env, C.OCI_DTYPE_INTERVAL_YM, C.size_t(unsafe.Sizeof(unsafe.Pointer(nil)))); ret.rv != C.OCI_SUCCESS { return nil, ociGetError(s.c.err) } else { oci8cols[i].kind = C.SQLT_INTERVAL_YM oci8cols[i].size = int(unsafe.Sizeof(unsafe.Pointer(nil))) oci8cols[i].pbuf = ret.extra *(*unsafe.Pointer)(ret.extra) = ret.ptr } case C.SQLT_RDD: // rowid lp = 40 oci8cols[i].pbuf = C.malloc(C.size_t(lp) + 1) oci8cols[i].kind = C.SQLT_CHR // tp oci8cols[i].size = int(lp + 1) default: oci8cols[i].pbuf = C.malloc(C.size_t(lp) + 1) oci8cols[i].kind = C.SQLT_CHR // tp oci8cols[i].size = int(lp + 1) } if rv := C.OCIDefineByPos( (*C.OCIStmt)(s.s), s.defp, (*C.OCIError)(s.c.err), C.ub4(i+1), oci8cols[i].pbuf, C.sb4(oci8cols[i].size), oci8cols[i].kind, unsafe.Pointer(&oci8cols[i].ind), &oci8cols[i].rlen, nil, C.OCI_DEFAULT); rv != C.OCI_SUCCESS { return nil, ociGetError(s.c.err) } } return &OCI8Rows{s, oci8cols, false}, nil }
// ColumnTypeDatabaseTypeName implement RowsColumnTypeDatabaseTypeName. func (rc *OCI8Rows) ColumnTypeDatabaseTypeName(i int) string { var p unsafe.Pointer var tp C.ub2 rp := C.WrapOCIParamGet(rc.s.s, C.OCI_HTYPE_STMT, (*C.OCIError)(rc.s.c.err), C.ub4(i+1)) if rp.rv == C.OCI_SUCCESS { p = rp.ptr } tpr := C.WrapOCIAttrGetUb2(p, C.OCI_DTYPE_PARAM, C.OCI_ATTR_DATA_TYPE, (*C.OCIError)(rc.s.c.err)) if tpr.rv == C.OCI_SUCCESS { tp = tpr.num } switch tp { case C.SQLT_CHR: return "SQLT_CHR" case C.SQLT_NUM: return "SQLT_NUM" case C.SQLT_INT: return "SQLT_INT" case C.SQLT_FLT: return "SQLT_FLT" case C.SQLT_STR: return "SQLT_STR" case C.SQLT_VNU: return "SQLT_VNU" case C.SQLT_LNG: return "SQLT_LNG" case C.SQLT_VCS: return "SQLT_VCS" case C.SQLT_DAT: return "SQLT_DAT" case C.SQLT_VBI: return "SQLT_VBI" case C.SQLT_BFLOAT: return "SQLT_BFLOAT" case C.SQLT_BDOUBLE: return "SQLT_BDOUBLE" case C.SQLT_BIN: return "SQLT_BIN" case C.SQLT_LBI: return "SQLT_LBI" case C.SQLT_UIN: return "SQLT_UIN" case C.SQLT_LVC: return "SQLT_LVC" case C.SQLT_LVB: return "SQLT_LVB" case C.SQLT_AFC: return "SQLT_AFC" case C.SQLT_AVC: return "SQLT_AVC" case C.SQLT_RDD: return "SQLT_RDD" case C.SQLT_NTY: return "SQLT_NTY" case C.SQLT_REF: return "SQLT_REF" case C.SQLT_CLOB: return "SQLT_CLOB" case C.SQLT_BLOB: return "SQLT_BLOB" case C.SQLT_FILE: return "SQLT_FILE" case C.SQLT_VST: return "SQLT_VST" case C.SQLT_ODT: return "SQLT_ODT" case C.SQLT_DATE: return "SQLT_DATE" case C.SQLT_TIMESTAMP: return "SQLT_TIMESTAMP" case C.SQLT_TIMESTAMP_TZ: return "SQLT_TIMESTAMP_TZ" case C.SQLT_INTERVAL_YM: return "SQLT_INTERVAL_YM" case C.SQLT_INTERVAL_DS: return "SQLT_INTERVAL_DS" case C.SQLT_TIMESTAMP_LTZ: return "SQLT_TIMESTAMP_LTZ" } return "" }