// intervalVarSetValue sets the value of the variable. func intervalVarSetValue(v *Variable, pos uint, value interface{}) error { var days, hours, minutes, seconds, microseconds C.sb4 x, ok := value.(time.Duration) if !ok { return fmt.Errorf("requires time.Duration, got %T", value) } days = C.sb4(x.Hours()) / 24 hours = C.sb4(x.Hours()) - days*24 minutes = C.sb4(x.Minutes() - x.Hours()*60) seconds = C.sb4(x.Seconds()-x.Minutes()) * 60 microseconds = C.sb4(float64(x.Nanoseconds()/1000) - x.Seconds()*1000*1000) if CTrace { ctrace("OCIIntervalSetDaySecond(env=%p, err=%p, days=%d, hours=%d, min=%d, sec=%d, micro=%d, handle=%p)", v.environment.handle, v.environment.errorHandle, days, hours, minutes, seconds, microseconds, v.getHandle(pos)) } return v.environment.CheckStatus( C.OCIIntervalSetDaySecond(unsafe.Pointer(v.environment.handle), v.environment.errorHandle, days, hours, minutes, seconds, microseconds, getIntervalHandle(v, pos)), "IntervalSetDaySecond") }
// Allocate a variable and bind it to the given statement. func (v *Variable) internalBind() (err error) { var status C.sword // perform the bind aL, rC := v.aLrC() allElts := C.ub4(0) //actElts := C.ub4(v.actualElements) pActElts := &v.actualElements if v.isArray { allElts = C.ub4(v.allocatedElements) } else { pActElts = nil } //log.Printf("%v isArray? %b allElts=%d", v.typ.Name, v.isArray, allElts) if v.boundName != "" { bname := []byte(v.boundName) if CTrace { ctrace("internalBind.OCIBindByName", v.boundCursorHandle, &v.bindHandle, v.environment.errorHandle, "name="+string(bname), len(bname), v.getDataArr(), v.bufferSize, v.typ.oracleType, v.indicator, aL, rC, allElts, pActElts, "DEFAULT") } status = C.OCIBindByName(v.boundCursorHandle, &v.bindHandle, v.environment.errorHandle, (*C.OraText)(&bname[0]), C.sb4(len(bname)), v.getDataArr(), C.sb4(v.bufferSize), v.typ.oracleType, unsafe.Pointer(&v.indicator[0]), aL, rC, allElts, pActElts, C.OCI_DEFAULT) } else { if CTrace { ctrace("internalBind.OCIBindByPos", v.boundCursorHandle, &v.bindHandle, v.environment.errorHandle, fmt.Sprintf("pos=%d", v.boundPos), "dataArr:", fmt.Sprintf("%x", v.dataBytes[:v.bufferSize]), "bufsize:", v.bufferSize, "typ:", v.typ.oracleType, v.indicator, aL, rC, allElts, pActElts, "DEFAULT") } status = C.OCIBindByPos(v.boundCursorHandle, &v.bindHandle, v.environment.errorHandle, C.ub4(v.boundPos), v.getDataArr(), C.sb4(v.bufferSize), v.typ.oracleType, unsafe.Pointer(&v.indicator[0]), aL, rC, allElts, pActElts, C.OCI_DEFAULT) } if err = v.environment.CheckStatus(status, "BindBy"); err != nil { return } // set the max data size for strings if (v.typ == StringVarType || v.typ == FixedCharVarType) && v.size > v.typ.size { err = v.environment.AttrSet( unsafe.Pointer(v.bindHandle), C.OCI_HTYPE_BIND, C.OCI_ATTR_MAXDATA_SIZE, unsafe.Pointer(&v.typ.size), C.sizeof_ub4) } return }
// beginRow allocates a handle for each column and fetches one row. func (rset *Rset) beginRow() (err error) { rset.log(_drv.cfg.Log.Rset.BeginRow) rset.Index++ // check is open if rset.ocistmt == nil { return errF("Rset is closed") } // allocate define descriptor handles for _, define := range rset.defs { //glog.Infof("Rset.define: ", define) rset.logF(_drv.cfg.Log.Rset.BeginRow, "%#v", define) err := define.alloc() if err != nil { return err } } // fetch one row r := C.OCIStmtFetch2( rset.ocistmt, //OCIStmt *stmthp, rset.stmt.ses.srv.env.ocierr, //OCIError *errhp, C.ub4(1), //ub4 nrows, C.OCI_FETCH_NEXT, //ub2 orientation, C.sb4(0), //sb4 fetchOffset, C.OCI_DEFAULT) //ub4 mode ); if r == C.OCI_ERROR { return rset.stmt.ses.srv.env.ociError() } else if r == C.OCI_NO_DATA { // Adjust Index so that Len() returns correct value when all rows read rset.Index-- // return io.EOF to conform with database/sql/driver return io.EOF } return nil }
func (s *OCI8Stmt) bind(args []driver.Value) error { if args == nil { return nil } var bp *C.OCIBind for i, v := range args { b := []byte(fmt.Sprintf("%v", v)) b = append(b, 0) rv := C.OCIBindByPos( (*C.OCIStmt)(s.s), &bp, (*C.OCIError)(s.c.err), C.ub4(i+1), unsafe.Pointer(&b[0]), C.sb4(len(b)), C.SQLT_STR, nil, nil, nil, 0, nil, OCI_MODE) if rv == C.OCI_ERROR { return ociGetError(s.c.err) } } return nil }
func (bnd *bndIntervalDS) bind(value IntervalDS, position int, stmt *Stmt) error { bnd.stmt = stmt r := C.OCIDescriptorAlloc( unsafe.Pointer(bnd.stmt.ses.srv.env.ocienv), //CONST dvoid *parenth, (*unsafe.Pointer)(unsafe.Pointer(&bnd.ociInterval)), //dvoid **descpp, C.OCI_DTYPE_INTERVAL_DS, //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 interval handle during bind") } r = C.OCIIntervalSetDaySecond( unsafe.Pointer(bnd.stmt.ses.srv.env.ocienv), //void *hndl, bnd.stmt.ses.srv.env.ocierr, //OCIError *err, C.sb4(value.Day), //sb4 dy, C.sb4(value.Hour), //sb4 hr, C.sb4(value.Minute), //sb4 mm, C.sb4(value.Second), //sb4 ss, C.sb4(value.Nanosecond), //sb4 fsec, bnd.ociInterval) //OCIInterval *result ); 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.ociInterval), //void *valuep, C.LENGTH_TYPE(unsafe.Sizeof(bnd.ociInterval)), //sb8 value_sz, C.SQLT_INTERVAL_DS, //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 }
// Set the value of the variable. func internalVar_SetValue(v *Variable, pos uint, value interface{}) error { var days, hours, minutes, seconds, microseconds C.sb4 x, ok := value.(time.Duration) if !ok { return fmt.Errorf("requires time.Duration, got %T", value) } days = C.sb4(x.Hours()) / 24 hours = C.sb4(x.Hours()) - days*24 minutes = C.sb4(x.Minutes() - x.Hours()*60) seconds = C.sb4(x.Seconds()-x.Minutes()) * 60 microseconds = C.sb4(float64(x.Nanoseconds()/1000) - x.Seconds()*1000*1000) return v.environment.CheckStatus( C.OCIIntervalSetDaySecond(unsafe.Pointer(v.environment.handle), v.environment.errorHandle, days, hours, minutes, seconds, microseconds, (*C.OCIInterval)(unsafe.Pointer(&v.dataBytes[pos*v.typ.size]))), "IntervalSetDaySecond") }
// OpenSrv connects to an Oracle server returning a *Srv and possible error. func (env *Env) OpenSrv(cfg *SrvCfg) (srv *Srv, err error) { env.mu.Lock() defer env.mu.Unlock() env.log(_drv.cfg.Log.Env.OpenSrv) err = env.checkClosed() if err != nil { return nil, errE(err) } if cfg == nil { return nil, er("Parameter 'cfg' may not be nil.") } // allocate server handle ocisrv, err := env.allocOciHandle(C.OCI_HTYPE_SERVER) if err != nil { return nil, errE(err) } // attach to server cDblink := C.CString(cfg.Dblink) defer C.free(unsafe.Pointer(cDblink)) r := C.OCIServerAttach( (*C.OCIServer)(ocisrv), //OCIServer *srvhp, env.ocierr, //OCIError *errhp, (*C.OraText)(unsafe.Pointer(cDblink)), //const OraText *dblink, C.sb4(len(cfg.Dblink)), //sb4 dblink_len, C.OCI_DEFAULT) //ub4 mode); if r == C.OCI_ERROR { return nil, errE(env.ociError()) } // allocate service context handle ocisvcctx, err := env.allocOciHandle(C.OCI_HTYPE_SVCCTX) if err != nil { return nil, errE(err) } // set server handle onto service context handle err = env.setAttr(ocisvcctx, C.OCI_HTYPE_SVCCTX, ocisrv, C.ub4(0), C.OCI_ATTR_SERVER) if err != nil { return nil, errE(err) } srv = _drv.srvPool.Get().(*Srv) // set *Srv srv.env = env srv.ocisrv = (*C.OCIServer)(ocisrv) srv.ocisvcctx = (*C.OCISvcCtx)(ocisvcctx) if srv.id == 0 { srv.id = _drv.srvId.nextId() } srv.cfg = *cfg if srv.cfg.StmtCfg == nil && srv.env.cfg.StmtCfg != nil { srv.cfg.StmtCfg = &(*srv.env.cfg.StmtCfg) // copy by value so that user may change independently } env.openSrvs.add(srv) return srv, nil }
func (stmt *statement) bind(args []driver.Value) error { var binding *C.OCIBind for pos, value := range args { buffer := []byte(fmt.Sprint("%v", value)) buffer = append(buffer, 0) result := C.OCIBindByPos((*C.OCIStmt)(stmt.handle), &binding, (*C.OCIError)(stmt.conn.err), C.ub4(pos+1), unsafe.Pointer(&buffer[0]), C.sb4(len(buffer)), C.SQLT_STR, nil, nil, nil, 0, nil, C.OCI_DEFAULT) if result != C.OCI_SUCCESS { return ociGetError(stmt.conn.err) } } return nil }
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 }
func (s *OCI8Stmt) bind(args []driver.Value) (boundParameters []oci8bind, err error) { if args == nil { return nil, nil } var ( dty C.ub2 cdata *C.char clen C.sb4 ) *s.bp = nil for i, v := range args { switch v.(type) { case nil: dty = C.SQLT_STR cdata = nil clen = 0 case []byte: v := v.([]byte) dty = C.SQLT_BIN cdata = CByte(v) clen = C.sb4(len(v)) boundParameters = append(boundParameters, oci8bind{dty, unsafe.Pointer(cdata)}) case float64: fb := math.Float64bits(v.(float64)) if fb&0x8000000000000000 != 0 { fb ^= 0xffffffffffffffff } else { fb |= 0x8000000000000000 } dty = C.SQLT_IBDOUBLE cdata = CByte([]byte{byte(fb >> 56), byte(fb >> 48), byte(fb >> 40), byte(fb >> 32), byte(fb >> 24), byte(fb >> 16), byte(fb >> 8), byte(fb)}) clen = 8 boundParameters = append(boundParameters, oci8bind{dty, unsafe.Pointer(cdata)}) case time.Time: var pt unsafe.Pointer var zp unsafe.Pointer now := v.(time.Time) _, offset := now.Zone() sign := '+' if offset < 0 { offset = -offset sign = '-' } offset /= 60 // oracle accepts zones "[+-]hh:mm" zone := fmt.Sprintf("%c%02d:%02d", sign, offset/60, offset%60) zoneTxt := now.Location().String() size := len(zoneTxt) if size < 8 { size = 8 } size += int(unsafe.Sizeof(unsafe.Pointer(nil))) if ret := C.WrapOCIDescriptorAlloc( s.c.env, C.OCI_DTYPE_TIMESTAMP_TZ, C.size_t(size)); ret.rv != C.OCI_SUCCESS { defer freeBoundParameters(boundParameters) return nil, ociGetError(s.c.err) } else { dty = C.SQLT_TIMESTAMP_TZ clen = C.sb4(unsafe.Sizeof(pt)) pt = ret.extra *(*unsafe.Pointer)(ret.extra) = ret.ptr zp = unsafe.Pointer(uintptr(ret.extra) + unsafe.Sizeof(unsafe.Pointer(nil))) boundParameters = append(boundParameters, oci8bind{dty, pt}) } for first := true; ; first = false { copy((*[1 << 30]byte)(zp)[0:len(zone)], zone) rv := C.OCIDateTimeConstruct( s.c.env, (*C.OCIError)(s.c.err), (*C.OCIDateTime)(*(*unsafe.Pointer)(pt)), C.sb2(now.Year()), C.ub1(now.Month()), C.ub1(now.Day()), C.ub1(now.Hour()), C.ub1(now.Minute()), C.ub1(now.Second()), C.ub4(now.Nanosecond()), (*C.OraText)(zp), C.size_t(len(zone)), ) if rv != C.OCI_SUCCESS { if !first { defer freeBoundParameters(boundParameters) return nil, ociGetError(s.c.err) } zone = zoneTxt } else { break } } cdata = (*C.char)(pt) case string: v := v.(string) dty = C.SQLT_AFC // don't trim strings !!! cdata = C.CString(v) clen = C.sb4(len(v)) boundParameters = append(boundParameters, oci8bind{dty, unsafe.Pointer(cdata)}) case int64: val := v.(int64) dty = C.SQLT_INT clen = C.sb4(8) // not tested on i386. may only work on amd64 cdata = (*C.char)(C.malloc(8)) buf := (*[1 << 30]byte)(unsafe.Pointer(cdata))[0:8] buf[0] = byte(val & 0x0ff) buf[1] = byte(val >> 8 & 0x0ff) buf[2] = byte(val >> 16 & 0x0ff) buf[3] = byte(val >> 24 & 0x0ff) buf[4] = byte(val >> 32 & 0x0ff) buf[5] = byte(val >> 40 & 0x0ff) buf[6] = byte(val >> 48 & 0x0ff) buf[7] = byte(val >> 56 & 0x0ff) boundParameters = append(boundParameters, oci8bind{dty, unsafe.Pointer(cdata)}) case bool: // oracle dont have bool, handle as 0/1 dty = C.SQLT_INT clen = C.sb4(1) cdata = (*C.char)(C.malloc(10)) if v.(bool) { *cdata = 1 } else { *cdata = 0 } boundParameters = append(boundParameters, oci8bind{dty, unsafe.Pointer(cdata)}) default: dty = C.SQLT_CHR d := fmt.Sprintf("%v", v) clen = C.sb4(len(d)) cdata = C.CString(d) boundParameters = append(boundParameters, oci8bind{dty, unsafe.Pointer(cdata)}) } if rv := C.OCIBindByPos( (*C.OCIStmt)(s.s), s.bp, (*C.OCIError)(s.c.err), C.ub4(i+1), unsafe.Pointer(cdata), clen, dty, nil, nil, nil, 0, nil, C.OCI_DEFAULT); rv != C.OCI_SUCCESS { defer freeBoundParameters(boundParameters) return nil, ociGetError(s.c.err) } } return boundParameters, nil }
// Connect to the database. // good minimal example: http://www.adp-gmbh.ch/ora/misc/oci/index.html func (conn *Connection) Connect(mode int64, twophase bool /*, newPassword string*/) error { credentialType := C.OCI_CRED_EXT var ( status C.sword err error ) defer func() { if err != nil { conn.Free(false) } }() // free handles conn.Free(false) // allocate the server handle if ociHandleAlloc(unsafe.Pointer(conn.environment.handle), C.OCI_HTYPE_SERVER, (*unsafe.Pointer)(unsafe.Pointer(&conn.serverHandle)), "Connect[allocate server handle]"); err != nil { return err } // attach to the server /* if (cxBuffer_FromObject(&buffer, self->dsn, self->environment->encoding) < 0) return -1; */ buffer := make([]byte, max(16, len(conn.dsn), len(conn.username), len(conn.password))+1) copy(buffer, []byte(conn.dsn)) buffer[len(conn.dsn)] = 0 // dsn := C.CString(conn.dsn) // defer C.free(unsafe.Pointer(dsn)) // Py_BEGIN_ALLOW_THREADS conn.srvMtx.Lock() // log.Printf("buffer=%s", buffer) status = C.OCIServerAttach(conn.serverHandle, conn.environment.errorHandle, (*C.OraText)(&buffer[0]), C.sb4(len(buffer)), C.OCI_DEFAULT) // Py_END_ALLOW_THREADS conn.srvMtx.Unlock() // cxBuffer_Clear(&buffer); if err = conn.environment.CheckStatus(status, "Connect[server attach]"); err != nil { return err } // log.Printf("attached to server %s", conn.serverHandle) // allocate the service context handle if err = ociHandleAlloc(unsafe.Pointer(conn.environment.handle), C.OCI_HTYPE_SVCCTX, (*unsafe.Pointer)(unsafe.Pointer(&conn.handle)), "Connect[allocate service context handle]"); err != nil { return err } // log.Printf("allocated service context handle") // set attribute for server handle if err = conn.AttrSet(C.OCI_ATTR_SERVER, unsafe.Pointer(conn.serverHandle), 0); err != nil { setErrAt(err, "Connect[set server handle]") return err } // set the internal and external names; these are needed for global // transactions but are limited in terms of the lengths of the strings if twophase { name := []byte("goracle") copy(buffer, name) buffer[len(name)] = 0 if err = conn.ServerAttrSet(C.OCI_ATTR_INTERNAL_NAME, unsafe.Pointer(&buffer[0]), len(name)); err != nil { setErrAt(err, "Connect[set internal name]") return err } if err = conn.ServerAttrSet(C.OCI_ATTR_EXTERNAL_NAME, unsafe.Pointer(&buffer[0]), len(name)); err != nil { setErrAt(err, "Connect[set external name]") return err } } // allocate the session handle if err = ociHandleAlloc(unsafe.Pointer(conn.environment.handle), C.OCI_HTYPE_SESSION, (*unsafe.Pointer)(unsafe.Pointer(&conn.sessionHandle)), "Connect[allocate session handle]"); err != nil { return err } // log.Printf("allocated session handle") // set user name in session handle if conn.username != "" { copy(buffer, []byte(conn.username)) buffer[len(conn.username)] = 0 credentialType = C.OCI_CRED_RDBMS if err = conn.SessionAttrSet(C.OCI_ATTR_USERNAME, unsafe.Pointer(&buffer[0]), len(conn.username)); err != nil { setErrAt(err, "Connect[set user name]") return err } //fmt.Printf("set user name %s\n", buffer) } // set password in session handle if conn.password != "" { copy(buffer, []byte(conn.password)) buffer[len(conn.password)] = 0 credentialType = C.OCI_CRED_RDBMS if err = conn.SessionAttrSet(C.OCI_ATTR_PASSWORD, unsafe.Pointer(&buffer[0]), len(conn.password)); err != nil { setErrAt(err, "Connect[set password]") return err } //fmt.Printf("set password %s\n", buffer) } /* #ifdef OCI_ATTR_DRIVER_NAME status = OCIAttrSet(self->sessionHandle, OCI_HTYPE_SESSION, (text*) DRIVER_NAME, strlen(DRIVER_NAME), OCI_ATTR_DRIVER_NAME, self->environment->errorHandle); if (Environment_CheckForError(self->environment, status, "Connection_Connect(): set driver name") < 0) return -1; #endif */ // set the session handle on the service context handle if err = conn.AttrSet(C.OCI_ATTR_SESSION, unsafe.Pointer(conn.sessionHandle), 0); err != nil { setErrAt(err, "Connect[set session handle]") return err } /* // if a new password has been specified, change it which will also // establish the session if (newPasswordObj) return Connection_ChangePassword(self, self->password, newPasswordObj); */ // begin the session // Py_BEGIN_ALLOW_THREADS conn.srvMtx.Lock() status = C.OCISessionBegin(conn.handle, conn.environment.errorHandle, conn.sessionHandle, C.ub4(credentialType), C.ub4(mode)) // Py_END_ALLOW_THREADS conn.srvMtx.Unlock() if err = conn.environment.CheckStatus(status, "Connect[begin session]"); err != nil { conn.sessionHandle = nil return err } return nil }
// Allocate a variable and bind it to the given statement. func (v *Variable) internalBind() (err error) { if CTrace { ctrace("%s.internalBind", v) } var status C.sword // perform the bind indic, aL, rC := v.aLrC() allElts := C.ub4(0) pActElts := &v.actualElements if v.isArray { allElts = C.ub4(v.allocatedElements) } else { pActElts = nil } //log.Printf("%v isArray? %b allElts=%d", v.typ.Name, v.isArray, allElts) var bindName string var bufSlice interface{} var m int if CTrace { m = int(v.bufferSize) if m > 40 { m = 40 } switch { case v.dataInts != nil: if m > len(v.dataInts) { m = len(v.dataInts) } bufSlice = v.dataInts[:m] case v.dataFloats != nil: if m > len(v.dataFloats) { m = len(v.dataFloats) } bufSlice = v.dataFloats[:m] default: if m > len(v.dataBytes) { m = len(v.dataBytes) } bufSlice = v.dataBytes[:m] } } if v.boundName != "" { bname := []byte(v.boundName) if CTrace { ctrace("internalBind.OCIBindByName(cur=%p, bind=%p, env=%p, name=%q, bufferSize=%d, oracleType=%d, data[:%d]=%v, indicator=%v, aL=%v, rC=%v, allElts=%v, pActElts=%v, DEFAULT)", v.boundCursorHandle, &v.bindHandle, v.environment.errorHandle, bname, v.bufferSize, v.typ.oracleType, m, bufSlice, v.indicator, aL, rC, allElts, pActElts) } bindName = fmt.Sprintf("%q", bname) status = C.OCIBindByName(v.boundCursorHandle, &v.bindHandle, v.environment.errorHandle, (*C.OraText)(&bname[0]), C.sb4(len(bname)), v.getDataArr(), C.sb4(v.bufferSize), v.typ.oracleType, indic, aL, rC, allElts, pActElts, C.OCI_DEFAULT) } else { if CTrace { m := int(v.bufferSize) if m > 40 { m = 40 } switch { case v.dataInts != nil: if m > len(v.dataInts) { m = len(v.dataInts) } bufSlice = v.dataInts[:m] case v.dataFloats != nil: if m > len(v.dataFloats) { m = len(v.dataFloats) } bufSlice = v.dataFloats[:m] default: if m > len(v.dataBytes) { m = len(v.dataBytes) } bufSlice = v.dataBytes[:m] } ctrace("internalBind.OCIBindByPos(cur=%p, boundPos=%d, data[:%d]=%v, bufSize=%d, oracleType=%d, indicator=%v, actLen=%v, rc=%p, allElts=%p pActElts=%p)", v.boundCursorHandle, v.boundPos, m, bufSlice, v.bufferSize, v.typ.oracleType, v.indicator, aL, rC, allElts, pActElts) } bindName = fmt.Sprintf("%d", v.boundPos) status = C.OCIBindByPos(v.boundCursorHandle, &v.bindHandle, v.environment.errorHandle, C.ub4(v.boundPos), v.getDataArr(), C.sb4(v.bufferSize), v.typ.oracleType, indic, aL, rC, allElts, pActElts, C.OCI_DEFAULT) } if err = v.environment.CheckStatus(status, fmt.Sprintf("BindBy(%s)", bindName)); err != nil { err = errgo.Mask(err) return } if v.typ.charsetForm != C.SQLCS_IMPLICIT { if err = v.environment.AttrSet( unsafe.Pointer(v.bindHandle), C.OCI_HTYPE_BIND, C.OCI_ATTR_CHARSET_FORM, unsafe.Pointer(&v.typ.size), C.sizeof_ub4); err != nil { err = errgo.Mask(err) return } // why do we set this here? if err = v.environment.AttrSet( unsafe.Pointer(v.bindHandle), C.OCI_HTYPE_BIND, C.OCI_ATTR_MAXDATA_SIZE, unsafe.Pointer(&v.bufferSize), C.sizeof_ub4); err != nil { err = errgo.Mask(err) return } } // set the max data size for strings if (v.typ == StringVarType || v.typ == FixedCharVarType) && v.size > v.typ.size { err = v.environment.AttrSet( unsafe.Pointer(v.bindHandle), C.OCI_HTYPE_BIND, C.OCI_ATTR_MAXDATA_SIZE, unsafe.Pointer(&v.typ.size), C.sizeof_ub4) } if err != nil { err = errgo.Mask(err) } return }
// Helper routine for Variable_Define() used so that constant calls to // OCIDescriptorFree() is not necessary. func (cur *Cursor) variableDefineHelper(param *C.OCIParam, position, numElements uint) (v *Variable, err error) { var size C.ub4 var varType *VariableType // determine data type varType, err = varTypeByOracleDescriptor(param, cur.environment) if err != nil { log.Printf("error determining data type: %s", err) return nil, err } // if (cursor->numbersAsStrings && varType == &vt_Float) // varType = &vt_NumberAsString; // retrieve size of the parameter size = C.ub4(varType.size) if varType.isVariableLength { var sizeFromOracle C.ub2 // determine the maximum length from Oracle if _, err = cur.environment.AttrGet( unsafe.Pointer(param), C.OCI_HTYPE_DESCRIBE, C.OCI_ATTR_DATA_SIZE, unsafe.Pointer(&sizeFromOracle), "data size"); err != nil { log.Printf("error getting data size: %+v", err) return nil, err } if CTrace { log.Printf("size of %p[%s] @ %d: %d", param, varType, position, sizeFromOracle) } // use the length from Oracle directly if available if uint(sizeFromOracle) > 0 { size = C.ub4(sizeFromOracle) } else if cur.outputSize >= 0 { // otherwise, use the value set with the setoutputsize() parameter if cur.outputSizeColumn < 0 || int(position) == cur.outputSizeColumn { size = C.ub4(cur.outputSize) } } } // create a variable of the correct type /* if cur.outputTypeHandler && cursor->outputTypeHandler != Py_None) var = Variable_NewByOutputTypeHandler(cursor, param, cursor->outputTypeHandler, varType, size, numElements); else if (cursor->connection->outputTypeHandler && cursor->connection->outputTypeHandler != Py_None) var = Variable_NewByOutputTypeHandler(cursor, param, cursor->connection->outputTypeHandler, varType, size, numElements); else */ //log.Printf("varType=%#v size=%d", varType, size) v, err = cur.NewVariable(numElements, varType, uint(size)) if err != nil { return nil, errgo.Newf("error creating variable: %s", err) } // call the procedure to set values prior to define if v.typ.preDefine != nil { if err = v.typ.preDefine(v, param); err != nil { return nil, errgo.Newf("error with preDefine(%s): %s", v, err) } } // perform the define //log.Printf("v=%#v", v) indic, aL, rC := v.aLrC() if CTrace { ctrace("OCIDefineByPos(cur=%p, defineHandle=%p, env=%p, position=%d, dataArr=%v, bufferSize=%d, oracleType=%d indicator=%v, aL=%v rC=%v, DEFAULT)", cur.handle, &v.defineHandle, v.environment.errorHandle, position, v.getDataArr(), v.bufferSize, v.typ.oracleType, v.indicator, aL, rC) } if err = cur.environment.CheckStatus( C.OCIDefineByPos(cur.handle, &v.defineHandle, v.environment.errorHandle, C.ub4(position), v.getDataArr(), C.sb4(v.bufferSize), v.typ.oracleType, indic, aL, rC, C.OCI_DEFAULT), "define"); err != nil { return nil, errgo.Newf("error defining: %s", err) } // call the procedure to set values after define if v.typ.postDefine != nil { if err = v.typ.postDefine(v); err != nil { return nil, errgo.Newf("error with postDefine(%s): %s", v, err) } } return v, nil }
func (s *OCI8Stmt) Query(args []driver.Value) (driver.Rows, error) { if err := s.bind(args); err != nil { return nil, err } var t C.int C.OCIAttrGet( s.s, C.OCI_HTYPE_STMT, unsafe.Pointer(&t), nil, C.OCI_ATTR_STMT_TYPE, (*C.OCIError)(s.c.err)) iter := C.ub4(1) if t == C.OCI_STMT_SELECT { iter = 0 } rv := C.OCIStmtExecute( (*C.OCIServer)(s.c.svc), (*C.OCIStmt)(s.s), (*C.OCIError)(s.c.err), iter, 0, nil, nil, OCI_MODE) if rv == C.OCI_ERROR { return nil, ociGetError(s.c.err) } var rc C.ub2 C.OCIAttrGet( s.s, C.OCI_HTYPE_STMT, unsafe.Pointer(&rc), nil, C.OCI_ATTR_PARAM_COUNT, (*C.OCIError)(s.c.err)) oci8cols := make([]oci8col, int(rc)) for i := 0; i < int(rc); i++ { var p unsafe.Pointer var np *C.char var ns C.ub4 var tp C.ub2 var lp C.ub2 C.OCIParamGet( s.s, C.OCI_HTYPE_STMT, (*C.OCIError)(s.c.err), (*unsafe.Pointer)(unsafe.Pointer(&p)), C.ub4(i+1)) C.OCIAttrGet( p, C.OCI_DTYPE_PARAM, unsafe.Pointer(&tp), nil, C.OCI_ATTR_DATA_TYPE, (*C.OCIError)(s.c.err)) C.OCIAttrGet( p, C.OCI_DTYPE_PARAM, unsafe.Pointer(&np), &ns, C.OCI_ATTR_NAME, (*C.OCIError)(s.c.err)) C.OCIAttrGet( p, C.OCI_DTYPE_PARAM, unsafe.Pointer(&lp), nil, C.OCI_ATTR_DATA_SIZE, (*C.OCIError)(s.c.err)) oci8cols[i].name = string((*[1 << 30]byte)(unsafe.Pointer(np))[0:int(ns)]) oci8cols[i].kind = int(tp) oci8cols[i].size = int(lp) oci8cols[i].pbuf = make([]byte, int(lp)+1) var defp *C.OCIDefine rv = C.OCIDefineByPos( (*C.OCIStmt)(s.s), &defp, (*C.OCIError)(s.c.err), C.ub4(i+1), unsafe.Pointer(&oci8cols[i].pbuf[0]), C.sb4(lp+1), C.SQLT_CHR, nil, nil, nil, OCI_MODE) if rv == C.OCI_ERROR { return nil, ociGetError(s.c.err) } } return &OCI8Rows{s, oci8cols, false}, nil }
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 }
func (s *OCI8Stmt) bind(args []namedValue) (boundParameters []oci8bind, err error) { if len(args) == 0 { return nil, nil } var ( dty C.ub2 cdata *C.char clen C.sb4 ) *s.bp = nil for i, uv := range args { switch v := uv.Value.(type) { case nil: dty = C.SQLT_STR cdata = nil clen = 0 case []byte: dty = C.SQLT_BIN cdata = CByte(v) clen = C.sb4(len(v)) boundParameters = append(boundParameters, oci8bind{dty, unsafe.Pointer(cdata)}) case float64: fb := math.Float64bits(v) if fb&0x8000000000000000 != 0 { fb ^= 0xffffffffffffffff } else { fb |= 0x8000000000000000 } dty = C.SQLT_IBDOUBLE cdata = CByte([]byte{byte(fb >> 56), byte(fb >> 48), byte(fb >> 40), byte(fb >> 32), byte(fb >> 24), byte(fb >> 16), byte(fb >> 8), byte(fb)}) clen = 8 boundParameters = append(boundParameters, oci8bind{dty, unsafe.Pointer(cdata)}) case time.Time: var pt unsafe.Pointer var zp unsafe.Pointer zone, offset := v.Zone() size := len(zone) if size < 8 { size = 8 } size += int(unsafe.Sizeof(unsafe.Pointer(nil))) if ret := C.WrapOCIDescriptorAlloc( s.c.env, C.OCI_DTYPE_TIMESTAMP_TZ, C.size_t(size)); ret.rv != C.OCI_SUCCESS { defer freeBoundParameters(boundParameters) return nil, ociGetError(ret.rv, s.c.err) } else { dty = C.SQLT_TIMESTAMP_TZ clen = C.sb4(unsafe.Sizeof(pt)) pt = ret.extra *(*unsafe.Pointer)(ret.extra) = ret.ptr zp = unsafe.Pointer(uintptr(ret.extra) + unsafe.Sizeof(unsafe.Pointer(nil))) boundParameters = append(boundParameters, oci8bind{dty, pt}) } tryagain := false copy((*[1 << 30]byte)(zp)[0:len(zone)], zone) rv := C.OCIDateTimeConstruct( s.c.env, (*C.OCIError)(s.c.err), (*C.OCIDateTime)(*(*unsafe.Pointer)(pt)), C.sb2(v.Year()), C.ub1(v.Month()), C.ub1(v.Day()), C.ub1(v.Hour()), C.ub1(v.Minute()), C.ub1(v.Second()), C.ub4(v.Nanosecond()), (*C.OraText)(zp), C.size_t(len(zone)), ) if rv != C.OCI_SUCCESS { tryagain = true } else { //check if oracle timezone offset is same ? rvz := C.WrapOCIDateTimeGetTimeZoneNameOffset( (*C.OCIEnv)(s.c.env), (*C.OCIError)(s.c.err), (*C.OCIDateTime)(*(*unsafe.Pointer)(pt))) if rvz.rv != C.OCI_SUCCESS { defer freeBoundParameters(boundParameters) return nil, ociGetError(rvz.rv, s.c.err) } if offset != int(rvz.h)*60*60+int(rvz.m)*60 { //fmt.Println("oracle timezone offset dont match", zone, offset, int(rvz.h)*60*60+int(rvz.m)*60) tryagain = true } } if tryagain { sign := '+' if offset < 0 { offset = -offset sign = '-' } offset /= 60 // oracle accept zones "[+-]hh:mm", try second time zone = fmt.Sprintf("%c%02d:%02d", sign, offset/60, offset%60) copy((*[1 << 30]byte)(zp)[0:len(zone)], zone) rv := C.OCIDateTimeConstruct( s.c.env, (*C.OCIError)(s.c.err), (*C.OCIDateTime)(*(*unsafe.Pointer)(pt)), C.sb2(v.Year()), C.ub1(v.Month()), C.ub1(v.Day()), C.ub1(v.Hour()), C.ub1(v.Minute()), C.ub1(v.Second()), C.ub4(v.Nanosecond()), (*C.OraText)(zp), C.size_t(len(zone)), ) if rv != C.OCI_SUCCESS { defer freeBoundParameters(boundParameters) return nil, ociGetError(rv, s.c.err) } } cdata = (*C.char)(pt) case string: dty = C.SQLT_AFC // don't trim strings !!! cdata = C.CString(v) clen = C.sb4(len(v)) boundParameters = append(boundParameters, oci8bind{dty, unsafe.Pointer(cdata)}) case int64: dty = C.SQLT_INT clen = C.sb4(8) // not tested on i386. may only work on amd64 cdata = (*C.char)(C.malloc(8)) buf := (*[1 << 30]byte)(unsafe.Pointer(cdata))[0:8] buf[0] = byte(v & 0x0ff) buf[1] = byte(v >> 8 & 0x0ff) buf[2] = byte(v >> 16 & 0x0ff) buf[3] = byte(v >> 24 & 0x0ff) buf[4] = byte(v >> 32 & 0x0ff) buf[5] = byte(v >> 40 & 0x0ff) buf[6] = byte(v >> 48 & 0x0ff) buf[7] = byte(v >> 56 & 0x0ff) boundParameters = append(boundParameters, oci8bind{dty, unsafe.Pointer(cdata)}) case bool: // oracle dont have bool, handle as 0/1 dty = C.SQLT_INT clen = C.sb4(1) cdata = (*C.char)(C.malloc(10)) if v { *cdata = 1 } else { *cdata = 0 } boundParameters = append(boundParameters, oci8bind{dty, unsafe.Pointer(cdata)}) default: dty = C.SQLT_CHR d := fmt.Sprintf("%v", v) clen = C.sb4(len(d)) cdata = C.CString(d) boundParameters = append(boundParameters, oci8bind{dty, unsafe.Pointer(cdata)}) } if uv.Name != "" { name := ":" + uv.Name cname := C.CString(name) defer C.free(unsafe.Pointer(cname)) if rv := C.OCIBindByName( (*C.OCIStmt)(s.s), s.bp, (*C.OCIError)(s.c.err), (*C.OraText)(unsafe.Pointer(cname)), C.sb4(len(name)), unsafe.Pointer(cdata), clen, dty, nil, nil, nil, 0, nil, C.OCI_DEFAULT); rv != C.OCI_SUCCESS { } } else { if rv := C.OCIBindByPos( (*C.OCIStmt)(s.s), s.bp, (*C.OCIError)(s.c.err), C.ub4(i+1), unsafe.Pointer(cdata), clen, dty, nil, nil, nil, 0, nil, C.OCI_DEFAULT); rv != C.OCI_SUCCESS { defer freeBoundParameters(boundParameters) return nil, ociGetError(rv, s.c.err) } } } return boundParameters, nil }
func (d *OCI8Driver) Open(dsnString string) (connection driver.Conn, err error) { var ( conn OCI8Conn dsn *DSN ) if dsn, err = ParseDSN(dsnString); err != nil { return nil, err } // set safe defaults conn.attrs = make(Values) conn.attrs.Set("prefetch_rows", 10) conn.attrs.Set("prefetch_memory", int64(0)) for k, v := range parseEnviron(os.Environ()) { conn.attrs.Set(k, v) } /* OCI_ENV_NO_MUTEX - No mutual exclusion (mutex) locking occurs in this mode. All OCI calls done on the environment handle, or on handles derived from the environment handle, must be serialized. OCI_THREADED must also be specified when OCI_ENV_NO_MUTEX is specified. */ rv := C.OCIEnvCreate( (**C.OCIEnv)(unsafe.Pointer(&conn.env)), C.OCI_THREADED|C.OCI_ENV_NO_MUTEX, nil, nil, nil, nil, 0, nil) if err := conn.check(rv, "Open.OCIEnvCreate"); err != nil { return nil, err } rv = C.OCIHandleAlloc( conn.env, &conn.err, C.OCI_HTYPE_ERROR, 0, nil) if err := conn.check(rv, "Open.OCIHandleAlloc conn.err"); err != nil { return nil, err } rv = C.OCIHandleAlloc( conn.env, &conn.srv, C.OCI_HTYPE_SERVER, 0, nil) if err := conn.check(rv, "Open.OCIHandleAlloc conn.srv"); err != nil { return nil, err } var phost *C.char if dsn.Host != "" { phost = C.CString(fmt.Sprintf("%s:%d/%s", dsn.Host, dsn.Port, dsn.SID)) } else { phost = C.CString(dsn.SID) } defer C.free(unsafe.Pointer(phost)) puser := C.CString(dsn.Username) defer C.free(unsafe.Pointer(puser)) ppass := C.CString(dsn.Password) defer C.free(unsafe.Pointer(ppass)) rv = C.OCIServerAttach( (*C.OCIServer)(conn.srv), (*C.OCIError)(conn.err), (*C.OraText)(unsafe.Pointer(phost)), C.sb4(C.strlen(phost)), 0, ) if err := conn.check(rv, "Open.OCIServerAttach"); err != nil { return nil, err } rv = C.OCIHandleAlloc( conn.env, &conn.svc, C.OCI_HTYPE_SVCCTX, 0, nil) if err := conn.check(rv, "Open.OCIHandleAlloc conn.svc"); err != nil { return nil, err } rv = C.OCIAttrSet( conn.svc, C.OCI_HTYPE_SVCCTX, conn.srv, 0, C.OCI_ATTR_SERVER, (*C.OCIError)(conn.err), ) if err := conn.check(rv, "Open.OCIAttrSet - srv"); err != nil { return nil, err } rv = C.OCIHandleAlloc( conn.env, &conn.usr, C.OCI_HTYPE_SESSION, 0, nil, ) if err := conn.check(rv, "Open.OCIHandleAlloc - usr"); err != nil { return nil, err } rv = C.OCIAttrSet( conn.usr, C.OCI_HTYPE_SESSION, unsafe.Pointer(puser), C.ub4(C.strlen(puser)), C.OCI_ATTR_USERNAME, (*C.OCIError)(conn.err), ) if err := conn.check(rv, "Open.OCIAttrSet - user"); err != nil { return nil, err } rv = C.OCIAttrSet( conn.usr, C.OCI_HTYPE_SESSION, unsafe.Pointer(ppass), C.ub4(C.strlen(ppass)), C.OCI_ATTR_PASSWORD, (*C.OCIError)(conn.err), ) if err := conn.check(rv, "Open.OCIAttrSet - ppass"); err != nil { return nil, err } rv = C.OCISessionBegin( (*C.OCISvcCtx)(conn.svc), (*C.OCIError)(conn.err), (*C.OCISession)(conn.usr), C.OCI_CRED_RDBMS, C.OCI_DEFAULT, ) if err := conn.check(rv, "Open.OCISessionBegin"); err != nil { return nil, err } rv = C.OCIAttrSet( conn.svc, C.OCI_HTYPE_SVCCTX, conn.usr, 0, C.OCI_ATTR_SESSION, (*C.OCIError)(conn.err), ) if err := conn.check(rv, "Open.OCIAttrSet svc"); err != nil { return nil, err } conn.location = dsn.Location conn.logDebug = dsn.LogDebug conn.logBadConn = dsn.LogBadConn return &conn, nil }
func (s *OCI8Stmt) Query(args []driver.Value) (rows driver.Rows, err error) { var ( freeBoundParameters func() ) if freeBoundParameters, err = s.bind(args); err != nil { return nil, err } defer freeBoundParameters() var t C.int C.OCIAttrGet( s.s, C.OCI_HTYPE_STMT, unsafe.Pointer(&t), nil, C.OCI_ATTR_STMT_TYPE, (*C.OCIError)(s.c.err)) iter := C.ub4(1) if t == C.OCI_STMT_SELECT { iter = 0 } // set the row prefetch. Only one extra row per fetch will be returned unless this is set. prefetch_size := C.ub4(s.c.attrs.Get("prefetch_rows").(int)) C.OCIAttrSet(s.s, C.OCI_HTYPE_STMT, unsafe.Pointer(&prefetch_size), 0, C.OCI_ATTR_PREFETCH_ROWS, (*C.OCIError)(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 prefetch_memory := C.ub4(s.c.attrs.Get("prefetch_memory").(int64)) C.OCIAttrSet(s.s, C.OCI_HTYPE_STMT, unsafe.Pointer(&prefetch_memory), 0, C.OCI_ATTR_PREFETCH_MEMORY, (*C.OCIError)(s.c.err)) rv := C.OCIStmtExecute( (*C.OCISvcCtx)(s.c.svc), (*C.OCIStmt)(s.s), (*C.OCIError)(s.c.err), iter, 0, nil, nil, C.OCI_DEFAULT) if rv == C.OCI_ERROR { return nil, ociGetError(s.c.err) } var rc C.ub2 C.OCIAttrGet( s.s, C.OCI_HTYPE_STMT, unsafe.Pointer(&rc), nil, C.OCI_ATTR_PARAM_COUNT, (*C.OCIError)(s.c.err)) oci8cols := make([]oci8col, int(rc)) for i := 0; i < int(rc); i++ { var p unsafe.Pointer var np *C.char var ns C.ub4 var tp C.ub2 var lp C.ub2 C.OCIParamGet( s.s, C.OCI_HTYPE_STMT, (*C.OCIError)(s.c.err), (*unsafe.Pointer)(unsafe.Pointer(&p)), C.ub4(i+1)) C.OCIAttrGet( p, C.OCI_DTYPE_PARAM, unsafe.Pointer(&tp), nil, C.OCI_ATTR_DATA_TYPE, (*C.OCIError)(s.c.err)) C.OCIAttrGet( p, C.OCI_DTYPE_PARAM, unsafe.Pointer(&np), &ns, C.OCI_ATTR_NAME, (*C.OCIError)(s.c.err)) C.OCIAttrGet( p, C.OCI_DTYPE_PARAM, unsafe.Pointer(&lp), nil, C.OCI_ATTR_DATA_SIZE, (*C.OCIError)(s.c.err)) switch tp { case C.SQLT_NUM: oci8cols[i].kind = C.SQLT_CHR default: oci8cols[i].kind = tp } oci8cols[i].name = string((*[1 << 30]byte)(unsafe.Pointer(np))[0:int(ns)]) oci8cols[i].size = int(lp) var defp *C.OCIDefine if tp == C.SQLT_CLOB || tp == C.SQLT_BLOB { rv = C.OCIDescriptorAlloc( s.c.env, &oci8cols[i].pbuf, C.OCI_DTYPE_LOB, 0, nil) if rv == C.OCI_ERROR { return nil, ociGetError(s.c.err) } rv = C.OCIDefineByPos( (*C.OCIStmt)(s.s), &defp, (*C.OCIError)(s.c.err), C.ub4(i+1), unsafe.Pointer(&oci8cols[i].pbuf), -1, oci8cols[i].kind, unsafe.Pointer(&oci8cols[i].ind), &oci8cols[i].rlen, nil, C.OCI_DEFAULT) } else { oci8cols[i].pbuf = C.malloc(C.size_t(lp) + 1) rv = C.OCIDefineByPos( (*C.OCIStmt)(s.s), &defp, (*C.OCIError)(s.c.err), C.ub4(i+1), oci8cols[i].pbuf, C.sb4(lp+1), oci8cols[i].kind, unsafe.Pointer(&oci8cols[i].ind), &oci8cols[i].rlen, nil, C.OCI_DEFAULT) } if rv == C.OCI_ERROR { return nil, ociGetError(s.c.err) } } return &OCI8Rows{s, oci8cols, false}, nil }
func (s *OCI8Stmt) bind(args []driver.Value) (freeBoundParameters func(), err error) { if args == nil { return func() {}, nil } var ( bp *C.OCIBind dty C.ub2 data []byte cdata *C.char boundParameters []oci8bind ) freeBoundParameters = func() { for _, col := range boundParameters { if col.pbuf != nil { if col.kind == C.SQLT_CLOB || col.kind == C.SQLT_BLOB { C.OCIDescriptorFree( col.pbuf, C.OCI_DTYPE_LOB) } else { C.free(col.pbuf) } } } } for i, v := range args { data = []byte{} switch v.(type) { case nil: dty = C.SQLT_STR boundParameters = append(boundParameters, oci8bind{dty, nil}) rv := C.OCIBindByPos( (*C.OCIStmt)(s.s), &bp, (*C.OCIError)(s.c.err), C.ub4(i+1), nil, 0, dty, nil, nil, nil, 0, nil, C.OCI_DEFAULT) if rv == C.OCI_ERROR { defer freeBoundParameters() return nil, ociGetError(s.c.err) } case []byte: // FIXME: Currently, CLOB not supported dty = C.SQLT_BLOB data = v.([]byte) var bamt C.ub4 var pbuf unsafe.Pointer rv := C.OCIDescriptorAlloc( s.c.env, &pbuf, C.OCI_DTYPE_LOB, 0, nil) if rv == C.OCI_ERROR { defer freeBoundParameters() return nil, ociGetError(s.c.err) } rv = C.OCILobCreateTemporary( (*C.OCISvcCtx)(s.c.svc), (*C.OCIError)(s.c.err), (*C.OCILobLocator)(pbuf), 0, C.SQLCS_IMPLICIT, C.OCI_TEMP_BLOB, C.OCI_ATTR_NOCACHE, C.OCI_DURATION_SESSION) if rv == C.OCI_ERROR { defer freeBoundParameters() return nil, ociGetError(s.c.err) } bamt = C.ub4(len(data)) rv = C.OCILobWrite( (*C.OCISvcCtx)(s.c.svc), (*C.OCIError)(s.c.err), (*C.OCILobLocator)(pbuf), &bamt, 1, unsafe.Pointer(&data[0]), C.ub4(len(data)), C.OCI_ONE_PIECE, nil, nil, 0, C.SQLCS_IMPLICIT) if rv == C.OCI_ERROR { defer freeBoundParameters() return nil, ociGetError(s.c.err) } boundParameters = append(boundParameters, oci8bind{dty, pbuf}) rv = C.OCIBindByPos( (*C.OCIStmt)(s.s), &bp, (*C.OCIError)(s.c.err), C.ub4(i+1), unsafe.Pointer(&pbuf), 0, dty, nil, nil, nil, 0, nil, C.OCI_DEFAULT) if rv == C.OCI_ERROR { defer freeBoundParameters() return nil, ociGetError(s.c.err) } 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), } cdata = C.CString(string(data)) boundParameters = append(boundParameters, oci8bind{dty, unsafe.Pointer(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)), dty, nil, nil, nil, 0, nil, C.OCI_DEFAULT) if rv == C.OCI_ERROR { defer freeBoundParameters() return nil, ociGetError(s.c.err) } default: dty = C.SQLT_STR data = []byte(fmt.Sprintf("%v", v)) data = append(data, 0) cdata = C.CString(string(data)) boundParameters = append(boundParameters, oci8bind{dty, unsafe.Pointer(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)), 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 }
func (s *StatementOracle) Next() (err int) { if !s.fetchDone { s.hDefine = new(C.OCIDefine) res := C.OCIStmtExecute(s.con.driver.hService, s.hStatement, s.con.driver.hError, 0, 0, nil, nil, C.OCI_DEFAULT) if C.OCI_SUCCESS != res && C.OCI_STILL_EXECUTING != res { fmt.Printf("Resultado OCIStmtExecute=%v\n", res) C.AuxOCIErrorGet(s.con.driver.hError) return -1 } s.fetchDone = true /* var idValue int res = C.OCIDefineByPos( s.hStatement, &s.hDefine, s.con.driver.hError, 1 /*pos* /, unsafe.Pointer(&idValue), C.sb4(unsafe.Sizeof(idValue)), C.SQLT_INT, nil, nil, nil, C.OCI_DEFAULT); if (C.OCI_SUCCESS != res /*&& C.OCI_STILL_EXECUTING != res* /) { fmt.Printf( "Resultado OCIDefineByPos=%v\n", res) C.AuxOCIErrorGet( s.con.driver.hError); return -2 } var surnameValue [40]C.char res = C.OCIDefineByPos( s.hStatement, &s.hDefine, s.con.driver.hError, 2 /*pos* /, unsafe.Pointer(&surnameValue[0]), C.sb4(unsafe.Sizeof(surnameValue)), C.SQLT_STR, nil, nil, nil, C.OCI_DEFAULT); if (C.OCI_SUCCESS != res /*&& C.OCI_STILL_EXECUTING != res* /) { fmt.Printf( "Resultado OCIDefineByPos=%v\n", res) C.AuxOCIErrorGet( s.con.driver.hError); return -3 } */ res = C.OCIAttrGet(unsafe.Pointer(s.hStatement), C.OCI_HTYPE_STMT, unsafe.Pointer(&s.numColumns), nil, C.OCI_ATTR_PARAM_COUNT, s.con.driver.hError) if C.OCI_SUCCESS != res /*&& C.OCI_STILL_EXECUTING != res*/ { fmt.Printf("Resultado OCIAttrGet=%v\n", res) C.AuxOCIErrorGet(s.con.driver.hError) return -3 } fmt.Printf("numColumns=%v\n", s.numColumns) s.columns = make([]*ColumnOracle, 0, 50) var hColumn C.ub4 pColumn := unsafe.Pointer(&hColumn) for i := 1; i <= s.numColumns; i++ { /* get parameter for column i */ res = C.OCIParamGet(unsafe.Pointer(s.hStatement), C.OCI_HTYPE_STMT, s.con.driver.hError, &pColumn, C.ub4(i)) if C.OCI_SUCCESS != res /*&& C.OCI_STILL_EXECUTING != res*/ { fmt.Printf("Resultado OCIParamGet=%v\n", res) C.AuxOCIErrorGet(s.con.driver.hError) return -4 } /* get data-type of column i */ var columnType C.ub2 pType := unsafe.Pointer(&columnType) res = C.OCIAttrGet(pColumn, C.OCI_DTYPE_PARAM, pType, nil, C.OCI_ATTR_DATA_TYPE, s.con.driver.hError) if C.OCI_SUCCESS != res /*&& C.OCI_STILL_EXECUTING != res*/ { fmt.Printf("Resultado OCIParamGet=%v\n", res) C.AuxOCIErrorGet(s.con.driver.hError) return -4 } size := C.ub4(100) var column_name_tmp *C.char res = C.OCIAttrGet(pColumn, C.OCI_DTYPE_PARAM, unsafe.Pointer(&column_name_tmp), nil, C.OCI_ATTR_NAME, s.con.driver.hError) fmt.Printf("coumnName (size=%v) = %v\n", size, column_name_tmp) //column_name_tmp[size] = 0 columnName := C.GoString(column_name_tmp) var columnSize int res = C.OCIAttrGet(pColumn, C.OCI_DTYPE_PARAM, unsafe.Pointer(&columnSize), nil, C.OCI_ATTR_DATA_SIZE, s.con.driver.hError) fmt.Printf("Column:%v Name:%v Size:%v Type:%v\n", i, columnName, columnSize, columnType) switch columnType { case C.SQLT_CHR: var columnValue = make([]C.char, columnSize+1) res = C.OCIDefineByPos(s.hStatement, &s.hDefine, s.con.driver.hError, C.ub4(i), /*pos*/ unsafe.Pointer(&columnValue[0]), C.sb4(columnSize), columnType, nil, nil, nil, C.OCI_DEFAULT) if C.OCI_SUCCESS != res /*&& C.OCI_STILL_EXECUTING != res*/ { fmt.Printf("Resultado OCIDefineByPos=%v\n", res) C.AuxOCIErrorGet(s.con.driver.hError) return -2 } s.columns = append(s.columns, NewColumnChrOracle(s, columnName, int(columnSize), columnValue)) case C.SQLT_NUM: var columnValue int res = C.OCIDefineByPos(s.hStatement, &s.hDefine, s.con.driver.hError, C.ub4(i), /*pos*/ unsafe.Pointer(&columnValue), C.sb4(4 /*sizeof(columnValue)*/), columnType, nil, nil, nil, C.OCI_DEFAULT) if C.OCI_SUCCESS != res /*&& C.OCI_STILL_EXECUTING != res*/ { fmt.Printf("Resultado OCIDefineByPos=%v\n", res) C.AuxOCIErrorGet(s.con.driver.hError) return -2 } s.columns = append(s.columns, NewColumnNumberOracle(s, columnName, int(columnSize), columnValue)) //case C.SQLT_LNG: //case C.SQLT_RID: //case C.SQLT_DAT: //case C.SQLT_BIN: //case C.SQLT_LBI: //case C.SQLT_AFC: //case C.SQLT_REF: //case C.SQLT_CLOB: //case C.SQLT_BLOB: //case C.SQLT_BFILEE: //case C.SQLT_TIMESTAMP: //case C.SQLT_TIME_TZ: //case C.SQLT_INTERVAL_YM: //case C.SQLT_INTERVAL_DS: //case C.SQLT_TIMESTAMP_LTZ: //case C.SQLT_RDD: default: s.columns = append(s.columns, NewColumnUnknownOracle(s, columnName, int(columnSize), int(columnType))) } fmt.Printf("Next len(stmt.columns)=%v\n", len(s.columns)) } //return 0 } res := C.OCIStmtFetch2(s.hStatement, s.con.driver.hError, 1 /*nrows*/, C.OCI_FETCH_NEXT, 0, C.OCI_DEFAULT) if C.OCI_SUCCESS != res && C.OCI_NO_DATA != res { fmt.Printf("Resultado OCIStmtFetch2=%v\n", res) C.AuxOCIErrorGet(s.con.driver.hError) return -4 } else if C.OCI_NO_DATA == res { //fmt.Printf( "The result is:%v-%v\n", idValue, C.GoString(&surnameValue[0])) return 0 } return 1 }
// Exec executes a query that may return rows, such as SELECT. func (stmt *statement) Query(v []driver.Value) (driver.Rows, error) { if err := stmt.bind(v); err != nil { return nil, err } // determine the type of statement. For select statements iter is set to zero, for other statements, only execute once. // * NOTE * Should an error be returned if the statement is a non-select type? var stmt_type C.int if C.OCIAttrGet(stmt.handle, C.OCI_HTYPE_STMT, unsafe.Pointer(&stmt_type), nil, C.OCI_ATTR_STMT_TYPE, (*C.OCIError)(stmt.conn.err)) != C.OCI_SUCCESS { log.Println(ociGetError(stmt.conn.err)) } iter := C.ub4(1) if stmt_type == C.OCI_STMT_SELECT { iter = 0 } // set the row prefetch. Only one extra row per fetch will be returned unless this is set. prefetchSize := C.ub4(100) if C.OCIAttrSet(stmt.handle, C.OCI_HTYPE_STMT, unsafe.Pointer(&prefetchSize), 0, C.OCI_ATTR_PREFETCH_ROWS, (*C.OCIError)(stmt.conn.err)) != C.OCI_SUCCESS { log.Println(ociGetError(stmt.conn.err)) } // execute the statement if C.OCIStmtExecute((*C.OCIServer)(stmt.conn.svr), (*C.OCIStmt)(stmt.handle), (*C.OCIError)(stmt.conn.err), iter, 0, nil, nil, C.OCI_DEFAULT) != C.OCI_SUCCESS { err := ociGetError(stmt.conn.err) log.Println(err) return nil, err } // find out how many output columns there are var cols C.ub2 if C.OCIAttrGet(stmt.handle, C.OCI_HTYPE_STMT, unsafe.Pointer(&cols), nil, C.OCI_ATTR_PARAM_COUNT, (*C.OCIError)(stmt.conn.err)) != C.OCI_SUCCESS { err := ociGetError(stmt.conn.err) log.Println(err) return nil, err } // build column meta-data columns := make([]column, int(cols)) for pos := 0; pos < int(cols); pos++ { col := &columns[pos] var param unsafe.Pointer var colType C.ub2 var colSize C.ub4 var colName *C.char var nameSize C.ub4 if C.OCIParamGet(stmt.handle, C.OCI_HTYPE_STMT, (*C.OCIError)(stmt.conn.err), (*unsafe.Pointer)(unsafe.Pointer(¶m)), C.ub4(pos+1)) != C.OCI_SUCCESS { err := ociGetError(stmt.conn.err) log.Println(err) return nil, err } C.OCIAttrGet(param, C.OCI_DTYPE_PARAM, unsafe.Pointer(&colType), nil, C.OCI_ATTR_DATA_TYPE, (*C.OCIError)(stmt.conn.err)) C.OCIAttrGet(param, C.OCI_DTYPE_PARAM, unsafe.Pointer(&colName), &nameSize, C.OCI_ATTR_NAME, (*C.OCIError)(stmt.conn.err)) C.OCIAttrGet(param, C.OCI_DTYPE_PARAM, unsafe.Pointer(&colSize), nil, C.OCI_ATTR_DATA_SIZE, (*C.OCIError)(stmt.conn.err)) col.kind = int(colType) col.size = int(colSize) col.name = C.GoStringN(colName, (C.int)(nameSize)) col.raw = make([]byte, int(colSize+1)) var def *C.OCIDefine result := C.OCIDefineByPos((*C.OCIStmt)(stmt.handle), &def, (*C.OCIError)(stmt.conn.err), C.ub4(pos+1), unsafe.Pointer(&col.raw[0]), C.sb4(colSize+1), C.SQLT_CHR, nil, nil, nil, C.OCI_DEFAULT) if result != C.OCI_SUCCESS { return nil, ociGetError(stmt.conn.err) } } return &rows{stmt, columns}, nil }
func (bnd *bndIntervalDSSlice) bind(values []IntervalDS, position int, stmt *Stmt) error { bnd.stmt = stmt bnd.ociIntervals = make([]*C.OCIInterval, len(values)) nullInds := make([]C.sb2, len(values)) alenp := make([]C.ACTUAL_LENGTH_TYPE, len(values)) rcodep := make([]C.ub2, len(values)) for n, value := range values { r := C.OCIDescriptorAlloc( unsafe.Pointer(bnd.stmt.ses.srv.env.ocienv), //CONST dvoid *parenth, (*unsafe.Pointer)(unsafe.Pointer(&bnd.ociIntervals[n])), //dvoid **descpp, C.OCI_DTYPE_INTERVAL_DS, //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 interval handle during bind") } r = C.OCIIntervalSetDaySecond( unsafe.Pointer(bnd.stmt.ses.srv.env.ocienv), //void *hndl, bnd.stmt.ses.srv.env.ocierr, //OCIError *err, C.sb4(value.Day), //sb4 dy, C.sb4(value.Hour), //sb4 hr, C.sb4(value.Minute), //sb4 mm, C.sb4(value.Second), //sb4 ss, C.sb4(value.Nanosecond), //sb4 fsec, bnd.ociIntervals[n]) //OCIInterval *result ); if r == C.OCI_ERROR { return bnd.stmt.ses.srv.env.ociError() } if values[n].IsNull { nullInds[n] = C.sb2(-1) } else { nullInds[n] = C.sb2(0) } alenp[n] = C.ACTUAL_LENGTH_TYPE(unsafe.Sizeof(bnd.ociIntervals[n])) } 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.ociIntervals[0]), //void *valuep, C.LENGTH_TYPE(unsafe.Sizeof(bnd.ociIntervals[0])), //sb8 value_sz, C.SQLT_INTERVAL_DS, //ub2 dty, unsafe.Pointer(&nullInds[0]), //void *indp, &alenp[0], //ub2 *alenp, &rcodep[0], //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() } r = C.OCIBindArrayOfStruct( bnd.ocibnd, bnd.stmt.ses.srv.env.ocierr, C.ub4(unsafe.Sizeof(bnd.ociIntervals[0])), //ub4 pvskip, C.ub4(C.sizeof_sb2), //ub4 indskip, C.ub4(C.sizeof_ub4), //ub4 alskip, C.ub4(C.sizeof_ub2)) //ub4 rcskip if r == C.OCI_ERROR { return bnd.stmt.ses.srv.env.ociError() } return nil }