Exemple #1
0
func (s *OCI8Stmt) Exec(args []driver.Value) (r driver.Result, err error) {
	var (
		freeBoundParameters func()
	)

	if freeBoundParameters, err = s.bind(args); err != nil {
		return nil, err
	}

	defer freeBoundParameters()

	rv := C.OCIStmtExecute(
		(*C.OCISvcCtx)(s.c.svc),
		(*C.OCIStmt)(s.s),
		(*C.OCIError)(s.c.err),
		1,
		0,
		nil,
		nil,
		C.OCI_DEFAULT)
	if rv == C.OCI_ERROR {
		return nil, ociGetError(s.c.err)
	}
	return &OCI8Result{s}, nil
}
Exemple #2
0
// Perform the work of executing a cursor and set the rowcount appropriately
// regardless of whether an error takes place.
func (cur *Cursor) internalExecute(numIters uint) error {
	var mode C.ub4

	if cur.connection.autocommit {
		mode = C.OCI_COMMIT_ON_SUCCESS
	} else {
		mode = C.OCI_DEFAULT
	}

	// Py_BEGIN_ALLOW_THREADS
	debug("%p.StmtExecute(%s, mode=%d) in internalExecute", cur,
		cur.statement, mode)
	if CTrace {
		ctrace("OCIStmtExecute", cur.connection.handle, cur.handle,
			cur.environment.errorHandle, numIters, 0, nil, nil, mode)
	}
	if err := cur.environment.CheckStatus(
		C.OCIStmtExecute(cur.connection.handle,
			cur.handle, cur.environment.errorHandle,
			C.ub4(numIters), 0, // iters, rowOff
			nil, nil, // snapIn, snapOut
			mode),
		"internalExecute"); err != nil {
		cur.setErrorOffset(err)
		return err
	}
	return cur.setRowCount()
}
Exemple #3
0
func (s *OCI8Stmt) Exec(args []driver.Value) (r driver.Result, err error) {
	var (
		freeBoundParameters func()
	)

	if freeBoundParameters, err = s.bind(args); err != nil {
		return nil, err
	}

	defer freeBoundParameters()

	mode := C.OCI_DEFAULT
	if !s.c.inTx {
		mode = C.OCI_COMMIT_ON_SUCCESS
	}
	rv := C.OCIStmtExecute(
		(*C.OCISvcCtx)(s.c.svc),
		(*C.OCIStmt)(s.s),
		(*C.OCIError)(s.c.err),
		1,
		0,
		nil,
		nil,
		(C.ub4)(mode))

	if err := s.c.check(rv, "OCI8Stmt.Exec"); err != nil {
		return nil, err
	}

	return &OCI8Result{s}, nil
}
Exemple #4
0
// Exec executes a query that doesn't return rows, such
// as an INSERT or UPDATE.
func (stmt *statement) Exec(args []driver.Value) (driver.Result, error) {
	if err := stmt.bind(args); err != nil {
		return nil, err
	}

	if C.OCIStmtExecute((*C.OCIServer)(stmt.conn.svr), (*C.OCIStmt)(stmt.handle), (*C.OCIError)(stmt.conn.err), 1, 0, nil, nil, C.OCI_DEFAULT) != C.OCI_SUCCESS {
		return nil, ociGetError(stmt.conn.err)
	}
	return &result{stmt}, nil
}
Exemple #5
0
// qry runs a SQL query on an Oracle server returning a *Rset and possible error.
func (stmt *Stmt) qry(params []interface{}) (rset *Rset, err error) {
	stmt.mu.Lock()
	defer stmt.mu.Unlock()
	defer func() {
		if value := recover(); value != nil {
			err = errR(value)
		}
	}()
	stmt.log(_drv.cfg.Log.Stmt.Qry)
	err = stmt.checkClosed()
	if err != nil {
		return nil, errE(err)
	}
	_, err = stmt.bind(params) // bind parameters
	if err != nil {
		return nil, errE(err)
	}
	err = stmt.setPrefetchSize() // set prefetch size
	if err != nil {
		return nil, errE(err)
	}
	// Query statement on Oracle server
	r := C.OCIStmtExecute(
		stmt.ses.ocisvcctx,      //OCISvcCtx           *svchp,
		stmt.ocistmt,            //OCIStmt             *stmtp,
		stmt.ses.srv.env.ocierr, //OCIError            *errhp,
		C.ub4(0),                //ub4                 iters,
		C.ub4(0),                //ub4                 rowoff,
		nil,                     //const OCISnapshot   *snap_in,
		nil,                     //OCISnapshot         *snap_out,
		C.OCI_DEFAULT)           //ub4                 mode );
	if r == C.OCI_ERROR {
		return nil, errE(stmt.ses.srv.env.ociError())
	}
	if stmt.hasPtrBind { // set any bind pointers
		err = stmt.setBindPtrs()
		if err != nil {
			return nil, errE(err)
		}
	}
	// create result set and open
	rset = _drv.rsetPool.Get().(*Rset)
	if rset.id == 0 {
		rset.id = _drv.rsetId.nextId()
	}
	err = rset.open(stmt, stmt.ocistmt)
	if err != nil {
		rset.close()
		return nil, errE(err)
	}
	stmt.openRsets.add(rset)

	return rset, nil
}
Exemple #6
0
func (s *OCI8Stmt) exec(ctx context.Context, args []namedValue) (r driver.Result, err error) {
	var (
		fbp []oci8bind
	)

	if fbp, err = s.bind(args); err != nil {
		return nil, err
	}

	defer freeBoundParameters(fbp)

	mode := C.ub4(C.OCI_DEFAULT)
	if s.c.inTransaction == false {
		mode = mode | C.OCI_COMMIT_ON_SUCCESS
	}

	done := make(chan struct{})
	defer close(done)
	go func() {
		select {
		case <-ctx.Done():
			C.OCIBreak(
				unsafe.Pointer(s.c.svc),
				(*C.OCIError)(s.c.err))
		case <-done:
		}
	}()

	rv := C.OCIStmtExecute(
		(*C.OCISvcCtx)(s.c.svc),
		(*C.OCIStmt)(s.s),
		(*C.OCIError)(s.c.err),
		1,
		0,
		nil,
		nil,
		mode)
	if rv != C.OCI_SUCCESS {
		return nil, ociGetError(rv, s.c.err)
	}

	n, en := s.rowsAffected()
	var id int64
	var ei error
	if n > 0 {
		id, ei = s.lastInsertId()
	}
	return &OCI8Result{s: s, n: n, errn: en, id: id, errid: ei}, nil
}
Exemple #7
0
func (s *OCI8Stmt) Exec(args []driver.Value) (r driver.Result, err error) {
	var (
		fbp []oci8bind
	)

	if fbp, err = s.bind(args); err != nil {
		return nil, err
	}

	defer freeBoundParameters(fbp)

	mode := C.ub4(C.OCI_DEFAULT)
	if s.c.inTransaction == false {
		mode = mode | C.OCI_COMMIT_ON_SUCCESS
	}

	rv := C.OCIStmtExecute(
		(*C.OCISvcCtx)(s.c.svc),
		(*C.OCIStmt)(s.s),
		(*C.OCIError)(s.c.err),
		1,
		0,
		nil,
		nil,
		mode)
	if rv != C.OCI_SUCCESS {
		return nil, ociGetError(s.c.err)
	}

	/*
		rv = C.OCIStmtFetch(
			(*C.OCIStmt)(s.s),
			(*C.OCIError)(s.c.err),
			1,
			C.OCI_FETCH_NEXT,
			C.OCI_DEFAULT)

		if rv == C.OCI_NO_DATA {
			return nil, io.EOF
		} else if rv != C.OCI_SUCCESS {
			return nil, ociGetError(s.c.err)
		}
		n, en := s.rowsAffected()
		id, ei := s.lastInsertId()
		return &OCI8Result{s: s, n: n, errn: en, id: id, errid: ei}, nil
	*/
	return &OCI8Result{s: s}, nil
}
Exemple #8
0
func (s *OCI8Stmt) Exec(args []driver.Value) (driver.Result, error) {
	if err := s.bind(args); err != nil {
		return nil, err
	}

	rv := C.OCIStmtExecute(
		(*C.OCIServer)(s.c.svc),
		(*C.OCIStmt)(s.s),
		(*C.OCIError)(s.c.err),
		1,
		0,
		nil,
		nil,
		OCI_MODE)
	if rv == C.OCI_ERROR {
		return nil, ociGetError(s.c.err)
	}
	return &OCI8Result{s}, nil
}
Exemple #9
0
// Parse the statement without executing it. This also retrieves information
// about the select list for select statements.
func (cur *Cursor) Parse(statement string) error {
	var mode C.ub4

	// statement text is expected
	if statement == "" {
		return nil
	}

	// make sure the cursor is open
	if !cur.isOpen {
		return nil
	}

	// prepare the statement
	if err := cur.internalPrepare(statement, ""); err != nil {
		return err
	}

	// parse the statement
	if cur.statementType == C.OCI_STMT_SELECT {
		mode = C.OCI_DESCRIBE_ONLY
	} else {
		mode = C.OCI_PARSE_ONLY
	}
	// Py_BEGIN_ALLOW_THREADS
	log.Printf("%p.StmtExecute(%s, mode=%d) in Parse", cur, cur.statement, mode)
	if CTrace {
		ctrace("OCIStmtExecute", cur.connection.handle, cur.handle,
			cur.environment.errorHandle, 0, 0, nil, nil, mode)
	}
	if err := cur.environment.CheckStatus(
		C.OCIStmtExecute(cur.connection.handle, cur.handle,
			cur.environment.errorHandle,
			0, 0, //iters, rowoff
			nil, nil, //snapIn, snapOut
			mode),
		"parse"); err != nil {
		// Py_END_ALLOW_THREADS
		return err
	}

	return nil
}
Exemple #10
0
// 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(&param)), 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
}
Exemple #11
0
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
}
Exemple #12
0
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
}
Exemple #13
0
// exe executes a SQL statement on an Oracle server returning rowsAffected, lastInsertId and error.
func (stmt *Stmt) exe(params []interface{}) (rowsAffected uint64, lastInsertId int64, err error) {
	stmt.mu.Lock()
	defer stmt.mu.Unlock()
	defer func() {
		if value := recover(); value != nil {
			err = errR(value)
		}
	}()
	stmt.log(_drv.cfg.Log.Stmt.Exe)
	err = stmt.checkClosed()
	if err != nil {
		return 0, 0, errE(err)
	}
	// for case of inserting and returning identity for database/sql package
	if _drv.sqlPkgEnv == stmt.ses.srv.env && stmt.stmtType == C.OCI_STMT_INSERT {
		lastIndex := strings.LastIndex(stmt.sql, ")")
		sqlEnd := stmt.sql[lastIndex+1 : len(stmt.sql)]
		sqlEnd = strings.ToUpper(sqlEnd)
		// add *int64 arg to capture identity
		if strings.Contains(sqlEnd, "RETURNING") {
			params[len(params)-1] = &lastInsertId
		}
	}
	iterations, err := stmt.bind(params) // bind parameters
	if err != nil {
		return 0, 0, errE(err)
	}
	err = stmt.setPrefetchSize() // set prefetch size
	if err != nil {
		return 0, 0, errE(err)
	}
	var mode C.ub4 // determine auto-commit state; don't auto-comit if there's an explicit user transaction occuring
	if stmt.cfg.IsAutoCommitting && stmt.ses.openTxs.len() == 0 {
		mode = C.OCI_COMMIT_ON_SUCCESS
	} else {
		mode = C.OCI_DEFAULT
	}
	// Execute statement on Oracle server
	r := C.OCIStmtExecute(
		stmt.ses.ocisvcctx,      //OCISvcCtx           *svchp,
		stmt.ocistmt,            //OCIStmt             *stmtp,
		stmt.ses.srv.env.ocierr, //OCIError            *errhp,
		C.ub4(iterations),       //ub4                 iters,
		C.ub4(0),                //ub4                 rowoff,
		nil,                     //const OCISnapshot   *snap_in,
		nil,                     //OCISnapshot         *snap_out,
		mode)                    //ub4                 mode );
	if r == C.OCI_ERROR {
		return 0, 0, errE(stmt.ses.srv.env.ociError())
	}
	var ub8RowsAffected C.ub8 // Get rowsAffected based on statement type
	switch stmt.stmtType {
	case C.OCI_STMT_SELECT, C.OCI_STMT_UPDATE, C.OCI_STMT_DELETE, C.OCI_STMT_INSERT:
		err := stmt.attr(unsafe.Pointer(&ub8RowsAffected), 8, C.OCI_ATTR_UB8_ROW_COUNT)
		if err != nil {
			return 0, 0, errE(err)
		}
		rowsAffected = uint64(ub8RowsAffected)
	case C.OCI_STMT_CREATE, C.OCI_STMT_DROP, C.OCI_STMT_ALTER, C.OCI_STMT_BEGIN:
	}
	if stmt.hasPtrBind { // Set any bind pointers
		err = stmt.setBindPtrs()
		if err != nil {
			return rowsAffected, lastInsertId, errE(err)
		}
	}
	return rowsAffected, lastInsertId, nil
}
Exemple #14
0
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 *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
}
Exemple #16
0
// Open defines select-list columns.
func (rset *Rset) open(stmt *Stmt, ocistmt *C.OCIStmt) error {
	rset.stmt = stmt
	rset.ocistmt = ocistmt
	rset.Index = -1
	rset.Err = nil
	rset.log(_drv.cfg.Log.Rset.Open) // call log after rset.stmt is set
	// get the implcit select-list describe information; no server round-trip
	r := C.OCIStmtExecute(
		rset.stmt.ses.srv.ocisvcctx,  //OCISvcCtx           *svchp,
		rset.ocistmt,                 //OCIStmt             *stmtp,
		rset.stmt.ses.srv.env.ocierr, //OCIError            *errhp,
		C.ub4(1),                     //ub4                 iters,
		C.ub4(0),                     //ub4                 rowoff,
		nil,                          //const OCISnapshot   *snap_in,
		nil,                          //OCISnapshot         *snap_out,
		C.OCI_DESCRIBE_ONLY)          //ub4                 mode );
	if r == C.OCI_ERROR {
		return rset.stmt.ses.srv.env.ociError()
	}
	// get the parameter count
	var paramCount C.ub4
	err := rset.attr(unsafe.Pointer(&paramCount), 4, C.OCI_ATTR_PARAM_COUNT)
	if err != nil {
		return err
	}
	// make defines slice
	rset.defs = make([]def, int(paramCount))
	rset.ColumnNames = make([]string, int(paramCount))
	rset.Row = make([]interface{}, int(paramCount))
	//fmt.Printf("rset.open (paramCount %v)\n", paramCount)

	// create parameters for each select-list column
	var gct GoColumnType
	for n := range rset.defs {
		// Create oci parameter handle; may be freed by OCIDescriptorFree()
		// parameter position is 1-based
		var ocipar *C.OCIParam
		r := C.OCIParamGet(
			unsafe.Pointer(rset.ocistmt),               //const void        *hndlp,
			C.OCI_HTYPE_STMT,                           //ub4               htype,
			rset.stmt.ses.srv.env.ocierr,               //OCIError          *errhp,
			(*unsafe.Pointer)(unsafe.Pointer(&ocipar)), //void              **parmdpp,
			C.ub4(n+1))                                 //ub4               pos );
		if r == C.OCI_ERROR {
			return rset.stmt.ses.srv.env.ociError()
		}
		// Get column size in bytes
		var columnSize uint32
		err = rset.paramAttr(ocipar, unsafe.Pointer(&columnSize), 0, C.OCI_ATTR_DATA_SIZE)
		if err != nil {
			return err
		}
		// Get oci data type code
		var ociTypeCode C.ub2
		err = rset.paramAttr(ocipar, unsafe.Pointer(&ociTypeCode), 0, C.OCI_ATTR_DATA_TYPE)
		if err != nil {
			return err
		}
		// Get column name
		var columnName *C.char
		err := rset.paramAttr(ocipar, unsafe.Pointer(&columnName), 0, C.OCI_ATTR_NAME)
		if err != nil {
			return err
		}
		rset.ColumnNames[n] = C.GoString(columnName)
		//fmt.Printf("Rset.open: ociTypeCode (%v)\n", ociTypeCode)
		//Log.Infof("Rset.open: ociTypeCode=%d name=%s size=%d", ociTypeCode, rset.ColumnNames[n], columnSize)
		//log(true, "ociTypeCode=", int(ociTypeCode), ", name=", rset.ColumnNames[n], ", size=", columnSize)
		switch ociTypeCode {
		case C.SQLT_NUM:
			// NUMBER
			// Get precision
			var precision C.sb2
			err = rset.paramAttr(ocipar, unsafe.Pointer(&precision), 0, C.OCI_ATTR_PRECISION)
			if err != nil {
				return err
			}
			// Get scale (the number of decimal places)
			var numericScale C.sb1
			err = rset.paramAttr(ocipar, unsafe.Pointer(&numericScale), 0, C.OCI_ATTR_SCALE)
			if err != nil {
				return err
			}
			// If the precision is nonzero and scale is -127, then it is a FLOAT;
			// otherwise, it's a NUMBER(precision, scale).
			if precision != 0 && (numericScale > 0 || numericScale == -127) {
				if stmt.gcts == nil || n >= len(stmt.gcts) || stmt.gcts[n] == D {
					if numericScale == -127 {
						gct = rset.stmt.cfg.Rset.float
					} else {
						gct = rset.stmt.cfg.Rset.numberFloat
					}
				} else {
					err = checkNumericColumn(stmt.gcts[n], rset.ColumnNames[n])
					if err != nil {
						return err
					}
					gct = stmt.gcts[n]
				}
				err := rset.defineNumeric(n, gct)
				if err != nil {
					return err
				}
			} else {
				if stmt.gcts == nil || n >= len(stmt.gcts) || stmt.gcts[n] == D {
					gct = rset.stmt.cfg.Rset.numberInt
				} else {
					err = checkNumericColumn(stmt.gcts[n], rset.ColumnNames[n])
					if err != nil {
						return err
					}
					gct = stmt.gcts[n]
				}
				err := rset.defineNumeric(n, gct)
				if err != nil {
					return err
				}
			}
		case C.SQLT_IBDOUBLE:
			// BINARY_DOUBLE
			if stmt.gcts == nil || n >= len(stmt.gcts) || stmt.gcts[n] == D {
				gct = rset.stmt.cfg.Rset.binaryDouble
			} else {
				err = checkNumericColumn(stmt.gcts[n], rset.ColumnNames[n])
				if err != nil {
					return err
				}
				gct = stmt.gcts[n]
			}
			err := rset.defineNumeric(n, gct)
			if err != nil {
				return err
			}
		case C.SQLT_IBFLOAT:
			// BINARY_FLOAT
			if stmt.gcts == nil || n >= len(stmt.gcts) || stmt.gcts[n] == D {
				gct = rset.stmt.cfg.Rset.binaryFloat
			} else {
				err = checkNumericColumn(stmt.gcts[n], rset.ColumnNames[n])
				if err != nil {
					return err
				}
				gct = stmt.gcts[n]
			}
			err := rset.defineNumeric(n, gct)
			if err != nil {
				return err
			}
		case C.SQLT_DAT, C.SQLT_TIMESTAMP, C.SQLT_TIMESTAMP_TZ, C.SQLT_TIMESTAMP_LTZ:
			// DATE, TIMESTAMP, TIMESTAMP WITH TIME ZONE, TIMESTAMP WITH LOCAL TIMEZONE
			if stmt.gcts == nil || n >= len(stmt.gcts) || stmt.gcts[n] == D {
				switch ociTypeCode {
				case C.SQLT_DAT:
					gct = rset.stmt.cfg.Rset.date
				case C.SQLT_TIMESTAMP:
					gct = rset.stmt.cfg.Rset.timestamp
				case C.SQLT_TIMESTAMP_TZ:
					gct = rset.stmt.cfg.Rset.timestampTz
				case C.SQLT_TIMESTAMP_LTZ:
					gct = rset.stmt.cfg.Rset.timestampLtz
				}
			} else {
				err = checkTimeColumn(stmt.gcts[n])
				if err != nil {
					return err
				}
				gct = stmt.gcts[n]
			}
			isNullable := false
			if gct == OraT {
				isNullable = true
			}
			def := rset.getDef(defIdxTime).(*defTime)
			rset.defs[n] = def
			err = def.define(n+1, isNullable, rset)
			if err != nil {
				return err
			}
		case C.SQLT_CHR:
			// VARCHAR, VARCHAR2, NVARCHAR2
			if stmt.gcts == nil || n >= len(stmt.gcts) || stmt.gcts[n] == D {
				gct = rset.stmt.cfg.Rset.varchar
			} else {
				err = checkStringColumn(stmt.gcts[n])
				if err != nil {
					return err
				}
				gct = stmt.gcts[n]
			}
			err = rset.defineString(n, columnSize, gct)
			if err != nil {
				return err
			}
		case C.SQLT_AFC:
			//Log.Infof("rset AFC size=%d gct=%v", columnSize, gct)
			// CHAR, NCHAR
			// for char(1 char) columns, columnSize is 4 (AL32UTF8 charset)
			if columnSize == 1 || columnSize == 4 {
				if stmt.gcts == nil || n >= len(stmt.gcts) || stmt.gcts[n] == D {
					gct = rset.stmt.cfg.Rset.char1
				} else {
					err = checkBoolOrStringColumn(stmt.gcts[n])
					if err != nil {
						return err
					}
					gct = stmt.gcts[n]
				}
				switch gct {
				case B, OraB:
					// Interpret single char as bool
					isNullable := false
					if gct == OraB {
						isNullable = true
					}
					def := rset.getDef(defIdxBool).(*defBool)
					rset.defs[n] = def
					err = def.define(n+1, int(columnSize), isNullable, rset)
					if err != nil {
						return err
					}
				case S, OraS:
					// Interpret single char as string
					rset.defineString(n, columnSize, gct)
				}
			} else {
				// Interpret as string
				if stmt.gcts == nil || n >= len(stmt.gcts) || stmt.gcts[n] == D {
					gct = rset.stmt.cfg.Rset.char
				} else {
					err = checkStringColumn(stmt.gcts[n])
					if err != nil {
						return err
					}
					gct = stmt.gcts[n]
				}
				err = rset.defineString(n, columnSize, gct)
				if err != nil {
					return err
				}
			}
		case C.SQLT_LNG:
			// LONG
			if stmt.gcts == nil || n >= len(stmt.gcts) || stmt.gcts[n] == D {
				gct = rset.stmt.cfg.Rset.long
			} else {
				err = checkStringColumn(stmt.gcts[n])
				if err != nil {
					return err
				}
				gct = stmt.gcts[n]
			}

			// longBufferSize: Use a moderate default buffer size; 2GB max buffer may not be feasible on all clients
			err = rset.defineString(n, stmt.cfg.longBufferSize, gct)
			if err != nil {
				return err
			}
		case C.SQLT_CLOB:
			// CLOB, NCLOB
			if stmt.gcts == nil || n >= len(stmt.gcts) || stmt.gcts[n] == D {
				gct = rset.stmt.cfg.Rset.clob
			} else {
				err = checkStringColumn(stmt.gcts[n])
				if err != nil {
					return err
				}
				gct = stmt.gcts[n]
			}
			// Get character set form
			var charsetForm C.ub1
			err = rset.paramAttr(ocipar, unsafe.Pointer(&charsetForm), 0, C.OCI_ATTR_CHARSET_FORM)
			if err != nil {
				return err
			}
			def := rset.getDef(defIdxLob).(*defLob)
			rset.defs[n] = def
			err = def.define(n+1, charsetForm, C.SQLT_CLOB, gct, rset)
			if err != nil {
				return err
			}
		case C.SQLT_BLOB:
			// BLOB
			if stmt.gcts == nil || n >= len(stmt.gcts) || stmt.gcts[n] == D {
				gct = rset.stmt.cfg.Rset.blob
			} else {
				err = checkBinColumn(stmt.gcts[n])
				if err != nil {
					return err
				}
				gct = stmt.gcts[n]
			}
			def := rset.getDef(defIdxLob).(*defLob)
			rset.defs[n] = def
			err = def.define(n+1, C.SQLCS_IMPLICIT, C.SQLT_BLOB, gct, rset)
			if err != nil {
				return err
			}
		case C.SQLT_BIN:
			// RAW
			if stmt.gcts == nil || n >= len(stmt.gcts) || stmt.gcts[n] == D {
				gct = rset.stmt.cfg.Rset.raw
			} else {
				err = checkBinColumn(stmt.gcts[n])
				if err != nil {
					return err
				}
				gct = stmt.gcts[n]
			}
			isNullable := false
			if gct == OraBin {
				isNullable = true
			}
			def := rset.getDef(defIdxRaw).(*defRaw)
			rset.defs[n] = def
			err = def.define(n+1, int(columnSize), isNullable, rset)
			if err != nil {
				return err
			}
		case C.SQLT_LBI:
			//log(true, "LONG RAW")
			// LONG RAW
			if stmt.gcts == nil || n >= len(stmt.gcts) || stmt.gcts[n] == D {
				gct = rset.stmt.cfg.Rset.longRaw
			} else {
				err = checkBinColumn(stmt.gcts[n])
				if err != nil {
					return err
				}
				gct = stmt.gcts[n]
			}
			isNullable := false
			if gct == OraBin {
				isNullable = true
			}
			def := rset.getDef(defIdxLongRaw).(*defLongRaw)
			rset.defs[n] = def
			err = def.define(n+1, rset.stmt.cfg.longRawBufferSize, isNullable, rset)
			if err != nil {
				return err
			}
		case C.SQLT_INTERVAL_YM:
			def := rset.getDef(defIdxIntervalYM).(*defIntervalYM)
			rset.defs[n] = def
			err = def.define(n+1, rset)
			if err != nil {
				return err
			}
		case C.SQLT_INTERVAL_DS:
			def := rset.getDef(defIdxIntervalDS).(*defIntervalDS)
			rset.defs[n] = def
			err = def.define(n+1, rset)
			if err != nil {
				return err
			}
		case C.SQLT_FILE:
			// BFILE
			def := rset.getDef(defIdxBfile).(*defBfile)
			rset.defs[n] = def
			err = def.define(n+1, rset)
			if err != nil {
				return err
			}
		case C.SQLT_RDD:
			// ROWID, UROWID
			def := rset.getDef(defIdxRowid).(*defRowid)
			rset.defs[n] = def
			err = def.define(n+1, rset)
			if err != nil {
				return err
			}
			break
		default:
			return errF("unsupported select-list column type (ociTypeCode: %v)", ociTypeCode)
		}
	}
	rset.logF(_drv.cfg.Log.Rset.OpenDefs, "%#v", rset.defs)
	return nil
}