8000 Added ref cursor sub query by MichaelS11 · Pull Request #383 · mattn/go-oci8 · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Added ref cursor sub query #383

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 25, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ services:
language: bash

before_install:
- docker pull wnameless/oracle-xe-11g
- docker run -d wnameless/oracle-xe-11g
- docker pull wnameless/oracle-xe-11g-r2
- docker run -d wnameless/oracle-xe-11g-r2

script:
- docker run --rm -i -e TESTDIR=$(pwd) -v $(pwd):$(pwd) wnameless/oracle-xe-11g /bin/bash < test.sh
- docker run --rm -i -e TESTDIR=$(pwd) -v $(pwd):$(pwd) wnameless/oracle-xe-11g-r2 /bin/bash < test.sh
28 changes: 17 additions & 11 deletions c_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,20 +72,24 @@ func cGoStringN(s *C.OraText, size int) string {

// freeDefines frees defines
func freeDefines(defines []oci8Define) {
for _, define := range defines {
if define.pbuf != nil {
freeBuffer(define.pbuf, define.dataType)
define.pbuf = nil
for i := 0; i < len(defines); i++ {
if len(defines[i].subDefines) > 0 {
freeDefines(defines[i].subDefines)
}
if define.length != nil {
C.free(unsafe.Pointer(define.length))
define.length = nil
defines[i].subDefines = nil
if defines[i].pbuf != nil {
freeBuffer(defines[i].pbuf, defines[i].dataType)
defines[i].pbuf = nil
}
if define.indicator != nil {
C.free(unsafe.Pointer(define.indicator))
define.indicator = nil
if defines[i].length != nil {
C.free(unsafe.Pointer(defines[i].length))
defines[i].length = nil
}
define.defineHandle = nil // should be freed by oci statement close
if defines[i].indicator != nil {
C.free(unsafe.Pointer(defines[i].indicator))
defines[i].indicator = nil
}
defines[i].defineHandle = nil // should be freed by oci statement close
}
}

Expand Down Expand Up @@ -124,6 +128,8 @@ func freeBuffer(buffer unsafe.Pointer, dataType C.ub2) {
C.OCIDescriptorFree(*(*unsafe.Pointer)(buffer), C.OCI_DTYPE_INTERVAL_DS)
case C.SQLT_INTERVAL_YM:
C.OCIDescriptorFree(*(*unsafe.Pointer)(buffer), C.OCI_DTYPE_INTERVAL_YM)
case C.SQLT_RSET:
C.OCIDescriptorFree(*(*unsafe.Pointer)(buffer), C.OCI_HTYPE_STMT)
default:
C.free(buffer)
}
Expand Down
2 changes: 1 addition & 1 deletion globals.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ type (
length *C.ub2
indicator *C.sb2
defineHandle *C.OCIDefine
subDefines []oci8Define
}

oci8Bind struct {
Expand All @@ -118,7 +119,6 @@ type (
OCI8Rows struct {
stmt *OCI8Stmt
defines []oci8Define
e bool
closed bool
ctx context.Context
}
Expand Down
149 changes: 149 additions & 0 deletions oci8_sql_number_go112_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
// +build go1.12

package oci8

import (
"context"
"database/sql"
"testing"
)

// TestDestructiveNumberCursor checks select cursor
func TestDestructiveNumberCursor(t *testing.T) {
if TestDisableDatabase || TestDisableDestructive {
t.SkipNow()
}

tableName := "number_cursor_" + TestTimeString
err := testExec(t, "create table "+tableName+" ( A INTEGER )", nil)
if err != nil {
t.Fatal("create table error:", err)
}

defer testDropTable(t, tableName)

testDestructiveNumberCursorInsert(t, tableName)

testDestructiveNumberCursorSelect(t, tableName)
}

func testDestructiveNumberCursorInsert(t *testing.T, tableName string) {
ctx, cancel := context.WithTimeout(context.Background(), TestContextTimeout)
stmt, err := TestDB.PrepareContext(ctx, "insert into "+tableName+" ( A ) values (:1)")
cancel()
if err != nil {
t.Fatal("prepare error:", err)
}

defer func() {
err = stmt.Close()
if err != nil {
if t.Failed() {
t.Logf("stmt close error: %v", err)
} else {
t.Fatal("stmt close error:", err)
}
}
}()

ctx, cancel = context.WithTimeout(context.Background(), TestContextTimeout)
_, err = stmt.ExecContext(ctx, 1)
cancel()
if err != nil {
t.Fatal("exec error:", err)
}

ctx, cancel = context.WithTimeout(context.Background(), TestContextTimeout)
_, err = stmt.ExecContext(ctx, 2)
cancel()
if err != nil {
stmt.Close()
t.Fatal("exec error:", err)
}
}

func testDestructiveNumberCursorSelect(t *testing.T, tableName string) {
ctx, cancel := context.WithTimeout(context.Background(), TestContextTimeout)
stmt, err := TestDB.PrepareContext(ctx, "select 1.5, cursor(select A from "+tableName+" order by A) from dual")
cancel()
if err != nil {
t.Fatal("prepare error:", err)
}

defer func() {
err = stmt.Close()
if err != nil {
if t.Failed() {
t.Logf("stmt close err: %v", err)
} else {
t.Fatal("stmt close error:", err)
}
}
}()

var rows *sql.Rows
ctx, cancel = context.WithTimeout(context.Background(), TestContextTimeout)
rows, err = stmt.QueryContext(ctx)
if err != nil {
cancel()
t.Fatal("query error:", err)
}

defer func() {
cancel()
err = rows.Close()
if err != nil {
if t.Failed() {
t.Logf("rows close error: %v", err)
} else {
t.Fatal("rows close error:", err)
}
}
}()

if !rows.Next() {
t.Fatal("expected row")
}

var float float64
var subRows *sql.Rows
err = rows.Scan(&float, &subRows)
if err != nil {
t.Fatal("scan error:", err)
}

if float != 1.5 {
t.Fatal("float != 1.5")
}

if subRows == nil {
t.Fatal("subRows is nil")
}

if !subRows.Next() {
t.Fatal("expected row")
}

var aInt int64
err = subRows.Scan(&aInt)
if err != nil {
t.Fatal("scan error:", err)
}

if aInt != 1 {
t.Fatal("aInt != 1")
}

if !subRows.Next() {
t.Fatal("expected row")
}

err = subRows.Scan(&aInt)
if err != nil {
t.Fatal("scan error:", err)
}

if aInt != 2 {
t.Fatal("aInt != 2")
}
}
22 changes: 20 additions & 2 deletions rows.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ func (rows *OCI8Rows) Close() error {
// Columns returns column names
func (rows *OCI8Rows) Columns() []string {
names := make([]string, len(rows.defines))
for i, define := range rows.defines {
names[i] = define.name
for i := 0; i < len(rows.defines); i++ {
names[i] = rows.defines[i].name
}
return names
}
Expand Down Expand Up @@ -199,6 +199,24 @@ func (rows *OCI8Rows) Next(dest []driver.Value) error {
}
dest[i] = (int64(years) * 12) + int64(months)

// SQLT_RSET - ref cursor
case C.SQLT_RSET:
stmtP := (**C.OCIStmt)(rows.defines[i].pbuf)
subStmt := &OCI8Stmt{conn: rows.stmt.conn, stmt: *stmtP}
if rows.defines[i].subDefines == nil {
var err error
rows.defines[i].subDefines, err = subStmt.makeDefines(rows.ctx)
if err != nil {
return err
}
}
subRows := &OCI8Rows{
stmt: subStmt,
defines: rows.defines[i].subDefines,
ctx: rows.ctx,
}
dest[i] = subRows

// default
default:
return fmt.Errorf("Unhandled column type: %d", rows.defines[i].dataType)
Expand Down
46 changes: 34 additions & 12 deletions statement.go
Original file line number Diff line number Diff line change
Expand Up @@ -424,8 +424,29 @@ func (stmt *OCI8Stmt) query(ctx context.Context, binds []oci8Bind) (driver.Rows,
return nil, err
}

var defines []oci8Define
defines, err = stmt.makeDefines(ctx)
if err != nil {
return nil, err
}

if ctx.Err() != nil {
freeDefines(defines)
return nil, ctx.Err()
}

rows := &OCI8Rows{
stmt: stmt,
defines: defines,
ctx: ctx,
}

return rows, nil
}

func (stmt *OCI8Stmt) makeDefines(ctx context.Context) ([]oci8Define, error) {
var paramCountUb4 C.ub4 // number of columns in the select-list
_, err = stmt.ociAttrGet(unsafe.Pointer(&paramCountUb4), C.OCI_ATTR_PARAM_COUNT)
_, err := stmt.ociAttrGet(unsafe.Pointer(&paramCountUb4), C.OCI_ATTR_PARAM_COUNT)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -597,6 +618,17 @@ func (stmt *OCI8Stmt) query(ctx context.Context, binds []oci8Bind) (driver.Rows,
defines[i].maxSize = 40
defines[i].pbuf = C.malloc(C.size_t(defines[i].maxSize))

case C.SQLT_RSET: // ref cursor
defines[i].dataType = dataType
defines[i].maxSize = C.sb4(sizeOfNilPointer)
var stmtP *unsafe.Pointer
stmtP, _, err = stmt.conn.ociHandleAlloc(C.OCI_HTYPE_STMT, 0)
if err != nil {
freeDefines(defines)
return nil, err
}
defines[i].pbuf = unsafe.Pointer(stmtP)

default:
defines[i].dataType = C.SQLT_AFC
defines[i].maxSize = C.sb4(maxSize)
Expand All @@ -622,17 +654,7 @@ func (stmt *OCI8Stmt) query(ctx context.Context, binds []oci8Bind) (driver.Rows,
}
}

if ctx.Err() != nil {
return nil, ctx.Err()
}

rows := &OCI8Rows{
stmt: stmt,
defines: defines,
ctx: ctx,
}

return rows, nil
return defines, nil
}

// getRowid returns the rowid
Expand Down
34 changes: 32 additions & 2 deletions test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,22 @@ apt-get -qq -y install git pkg-config gcc wget 2>&1 > /dev/null

echo "installing go"
cd /tmp/
wget -nv https://dl.google.com/go/go1.11.5.linux-amd64.tar.gz
wget -nv https://dl.google.com/go/go1.13.8.linux-amd64.tar.gz
wget -nv https://dl.google.com/go/go1.12.17.linux-amd64.tar.gz
wget -nv https://dl.google.com/go/go1.11.13.linux-amd64.tar.gz
wget -nv https://dl.google.com/go/go1.10.8.linux-amd64.tar.gz
wget -nv https://dl.google.com/go/go1.9.7.linux-amd64.tar.gz

mkdir -p /usr/local/goFiles1.13.x
tar -xf /tmp/go1.13.8.linux-amd64.tar.gz
mv /tmp/go /usr/local/go1.13.x

mkdir -p /usr/local/goFiles1.12.x
tar -xf /tmp/go1.12.17.linux-amd64.tar.gz
mv /tmp/go /usr/local/go1.12.x

mkdir -p /usr/local/goFiles1.11.x
tar -xf /tmp/go1.11.5.linux-amd64.tar.gz
tar -xf /tmp/go1.11.13.linux-amd64.tar.gz
mv /tmp/go /usr/local/go1.11.x

mkdir -p /usr/local/goFiles1.10.x
Expand Down Expand Up @@ -64,6 +74,26 @@ PKGCONFIG
export PATH_SAVE=${PATH}


echo "testing go-oci8 Go 1.13.x"
export PATH=/usr/local/go1.13.x/bin:${PATH_SAVE}
export GOROOT=/usr/local/go1.13.x
export GOPATH=/usr/local/goFiles1.13.x
mkdir -p ${GOPATH}/src/github.com/mattn/go-oci8
cp -r ${TESTDIR}/* ${GOPATH}/src/github.com/mattn/go-oci8/

go test -v github.com/mattn/go-oci8 -args -disableDatabase=false -hostValid ${DOCKER_IP} -username scott -password tiger


echo "testing go-oci8 Go 1.12.x"
export PATH=/usr/local/go1.12.x/bin:${PATH_SAVE}
export GOROOT=/usr/local/go1.12.x
export GOPATH=/usr/local/goFiles1.12.x
mkdir -p ${GOPATH}/src/github.com/mattn/go-oci8
cp -r ${TESTDIR}/* ${GOPATH}/src/github.com/mattn/go-oci8/

go test -v github.com/mattn/go-oci8 -args -disableDatabase=false -hostValid ${DOCKER_IP} -username scott -password tiger


echo "testing go-oci8 Go 1.11.x"
export PATH=/usr/local/go1.11.x/bin:${PATH_SAVE}
export GOROOT=/usr/local/go1.11.x
Expand Down
0