Skip to content

Commit 8b842f2

Browse files
authored
Merge pull request #381 from MichaelS11/OCIStmtPrepare2
Switched to OCIStmtPrepare2 & Improve context done
2 parents aaa5bac + e24785c commit 8b842f2

File tree

4 files changed

+61
-40
lines changed

4 files changed

+61
-40
lines changed

connection.go

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import (
1616
// Ping database connection
1717
func (conn *OCI8Conn) Ping(ctx context.Context) error {
1818
done := make(chan struct{})
19-
go conn.ociBreak(ctx, done)
19+
go conn.ociBreakDone(ctx, done)
2020
result := C.OCIPing(conn.svc, conn.errHandle, C.OCI_DEFAULT)
2121
close(done)
2222
if result == C.OCI_SUCCESS || result == C.OCI_SUCCESS_WITH_INFO {
@@ -96,24 +96,23 @@ func (conn *OCI8Conn) PrepareContext(ctx context.Context, query string) (driver.
9696
defer C.free(unsafe.Pointer(queryP))
9797

9898
// statement handle
99-
stmt, _, err := conn.ociHandleAlloc(C.OCI_HTYPE_STMT, 0)
100-
if err != nil {
101-
return nil, fmt.Errorf("allocate statement handle error: %v", err)
102-
}
103-
104-
if rv := C.OCIStmtPrepare(
105-
(*C.OCIStmt)(*stmt),
106-
conn.errHandle,
107-
queryP,
108-
C.ub4(len(query)),
109-
C.ub4(C.OCI_NTV_SYNTAX),
110-
C.ub4(C.OCI_DEFAULT),
99+
var stmtTemp *C.OCIStmt
100+
stmt := &stmtTemp
101+
if rv := C.OCIStmtPrepare2(
102+
conn.svc, // service context handle
103+
stmt, // pointer to the statement handle returned
104+
conn.errHandle, // error handle
105+
queryP, // statement text
106+
C.ub4(len(query)), // statement text length
107+
nil, // key to be used for searching the statement in the statement cache
108+
C.ub4(0), // length of the key
109+
C.ub4(C.OCI_NTV_SYNTAX), // syntax - OCI_NTV_SYNTAX: syntax depends upon the version of the server
110+
C.ub4(C.OCI_DEFAULT), // mode
111111
); rv != C.OCI_SUCCESS {
112-
C.OCIHandleFree(*stmt, C.OCI_HTYPE_STMT)
113112
return nil, conn.getError(rv)
114113
}
115114

116-
return &OCI8Stmt{conn: conn, stmt: (*C.OCIStmt)(*stmt)}, nil
115+
return &OCI8Stmt{conn: conn, stmt: *stmt}, nil
117116
}
118117

119118
// Begin starts a transaction
@@ -567,23 +566,28 @@ func appendSmallInt(slice []byte, num int) []byte {
567566
return append(slice, byte('0'+num/10), byte('0'+(num%10)))
568567
}
569568

570-
// ociBreak calls OCIBreak if ctx.Done is finished before done chan is closed
571-
func (conn *OCI8Conn) ociBreak(ctx context.Context, done chan struct{}) {
569+
// ociBreakDone calls OCIBreak if ctx.Done is finished before done chan is closed
570+
func (conn *OCI8Conn) ociBreakDone(ctx context.Context, done chan struct{}) {
572571
select {
573572
case <-done:
574573
case <-ctx.Done():
575574
// select again to avoid race condition if both are done
576575
select {
577576
case <-done:
578577
default:
579-
result := C.OCIBreak(
580-
unsafe.Pointer(conn.svc), // The service context handle or the server context handle.
581-
conn.errHandle, // An error handle
582-
)
583-
err := conn.getError(result)
584-
if err != nil {
585-
conn.logger.Print("OCIBreak error: ", err)
586-
}
578+
conn.ociBreak()
587579
}
588580
}
589581
}
582+
583+
// ociBreak calls OCIBreak
584+
func (conn *OCI8Conn) ociBreak() {
585+
result := C.OCIBreak(
586+
unsafe.Pointer(conn.svc), // service or server context handle
587+
conn.errHandle, // error handle
588+
)
589+
err := conn.getError(result)
590+
if err != nil {
591+
conn.logger.Print("OCIBreak error: ", err)
592+
}
593+
}

globals.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import "C"
99
// noPkgConfig is a Go tag for disabling using pkg-config and using environmental settings like CGO_CFLAGS and CGO_LDFLAGS instead
1010

1111
import (
12+
"context"
1213
"database/sql"
1314
"errors"
1415
"io/ioutil"
@@ -82,7 +83,6 @@ type (
8283
conn *OCI8Conn
8384
stmt *C.OCIStmt
8485
closed bool
85-
pbind []oci8Bind // bind params
8686
}
8787

8888
// OCI8Result is Oracle result
@@ -120,6 +120,7 @@ type (
120120
defines []oci8Define
121121
e bool
122122
closed bool
123+
ctx context.Context
123124
done chan struct{}
124125
}
125126
)

rows.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ func (rows *OCI8Rows) Next(dest []driver.Value) error {
4343
return nil
4444
}
4545

46+
if rows.ctx.Err() != nil {
47+
return rows.ctx.Err()
48+
}
49+
4650
result := C.OCIStmtFetch2(
4751
rows.stmt.stmt,
4852
rows.stmt.conn.errHandle,
@@ -198,7 +202,6 @@ func (rows *OCI8Rows) Next(dest []driver.Value) error {
198202
return fmt.Errorf("Unhandled column type: %d", rows.defines[i].dataType)
199203

200204
}
201-
202205
}
203206

204207
return nil

statement.go

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,16 @@ func (stmt *OCI8Stmt) Close() error {
2222
}
2323
stmt.closed = true
2424

25-
C.OCIHandleFree(unsafe.Pointer(stmt.stmt), C.OCI_HTYPE_STMT)
26-
25+
result := C.OCIStmtRelease(
26+
stmt.stmt, // statement handle
27+
stmt.conn.errHandle, // error handle
28+
nil, // key to be associated with the statement in the cache
29+
C.ub4(0), // length of the key
30+
C.ub4(C.OCI_DEFAULT), // mode
31+
)
2732
stmt.stmt = nil
28-
stmt.pbind = nil
2933

30-
return nil
34+
return stmt.conn.getError(result)
3135
}
3236

3337
// NumInput returns the number of input
@@ -66,11 +70,9 @@ func (stmt *OCI8Stmt) bindValues(ctx context.Context, values []driver.Value, nam
6670
}
6771

6872
for i := 0; i < count; i++ {
69-
select {
70-
case <-ctx.Done():
73+
if ctx.Err() != nil {
7174
freeBinds(binds)
7275
return nil, ctx.Err()
73-
default:
7476
}
7577

7678
var valueInterface interface{}
@@ -410,8 +412,12 @@ func (stmt *OCI8Stmt) query(ctx context.Context, binds []oci8Bind) (driver.Rows,
410412
mode = mode | C.OCI_COMMIT_ON_SUCCESS
411413
}
412414

415+
if ctx.Err() != nil {
416+
return nil, ctx.Err()
417+
}
418+
413419
done := make(chan struct{})
414-
go stmt.conn.ociBreak(ctx, done)
420+
go stmt.conn.ociBreakDone(ctx, done)
415421
err = stmt.ociStmtExecute(iter, mode)
416422
close(done)
417423
if err != nil {
@@ -428,11 +434,9 @@ func (stmt *OCI8Stmt) query(ctx context.Context, binds []oci8Bind) (driver.Rows,
428434
defines := make([]oci8Define, paramCount)
429435

430436
for i := 0; i < paramCount; i++ {
431-
select {
432-
case <-ctx.Done():
437+
if ctx.Err() != nil {
433438
freeDefines(defines)
434439
return nil, ctx.Err()
435-
default:
436440
}
437441

438442
var param *C.OCIParam
@@ -618,13 +622,18 @@ func (stmt *OCI8Stmt) query(ctx context.Context, binds []oci8Bind) (driver.Rows,
618622
}
619623
}
620624

625+
if ctx.Err() != nil {
626+
return nil, ctx.Err()
627+
}
628+
621629
rows := &OCI8Rows{
622630
stmt: stmt,
623631
defines: defines,
632+
ctx: ctx,
624633
done: make(chan struct{}),
625634
}
626635

627-
go stmt.conn.ociBreak(ctx, rows.done)
636+
go stmt.conn.ociBreakDone(ctx, rows.done)
628637

629638
return rows, nil
630639
}
@@ -692,8 +701,12 @@ func (stmt *OCI8Stmt) exec(ctx context.Context, binds []oci8Bind) (driver.Result
692701
mode = mode | C.OCI_COMMIT_ON_SUCCESS
693702
}
694703

704+
if ctx.Err() != nil {
705+
return nil, ctx.Err()
706+
}
707+
695708
done := make(chan struct{})
696-
go stmt.conn.ociBreak(ctx, done)
709+
go stmt.conn.ociBreakDone(ctx, done)
697710
err := stmt.ociStmtExecute(1, mode)
698711
close(done)
699712
if err != nil && err != ErrOCISuccessWithInfo {

0 commit comments

Comments
 (0)